Type Transformations Workshop (9 exercises)
solution

Prevent Unwanted Type Scenarios from Happening

There's a lot going on to this solution, so let's construct it from scratch.

Here's our starting point:

The first thing we want to do is check if T extends "hello" or "goodbye". For now we'll say if does that we'll return "wow", and if it doesn't we'll return never:

We can test this with an Example type to see if we pass this initial check by hovering:

Using a union type like this allows saves us from having to say "if T extends hello do something, otherwise if T extends goodbye do something."

Now the we know our check works, we can replace "wow" with a nested ternary that contains the logic of what to return for "hello" or "goodbye" being passed in:

Now when our tests pass in "alright pal" or 1, we'll end up in the never branch instead of the branch where our actual logic is.

Conditional Types and never

There's no limit to how many conditional types you can stack.

In fact, a lot of the complicated libraries use these huge stacks of conditional types that are ugly to look at but kind of drive a lot of the complex logic.

The pattern of returning never allows our conditional types to specify their "else" logic without having to worry too much about what it is. If you try to use something that's been typed as never you will get an error.

We'll look at never again in later exercises.

Transcript

[0:00] [0: 00] Oh, boy. Here we go. This, YouSayGoodbyeAndISayHello, we're now, first of all, checking this. This looks a little bit crazy. In fact, let me construct this from scratch so you understand. I'm going to, first of all, say -- this is what the problem started with -- we want to first check if T extends hello or goodbye.
[0:23] [0: 25] If it does, then let's just say we return wow. Otherwise, we're going to return never. Now, if I say type Example = YouSayGoodbyeAndISayHello, and I pass in whatever, then this doesn't extend this, so we're getting a never here. Whereas, if I say, hello, then we should say wow. If I say goodbye, then it's going to say wow as well.

[0:50] [0: 51] We now know what we can make pass this initial check here. It's kind of cool that we get to use a union type here. We don't need to say T extends hello, then do something, and otherwise T extends goodbye, and do something. We can say T extends hello or goodbye, and then we can enter that branch.

[1:09] [1: 09] Inside here, we can say T extends hello, then return goodbye, otherwise return hello. We end up with the kind of monstrosity that we have here. That means now that when we pass in something weird, we're going to hit this never branch instead of the branch that contains our actual logic.

[1:28] [1: 28] There's no limits here to how many of these you can stack. In fact, a lot of the really, really complicated libraries use these huge stacks of conditional types that are ugly as hell to look at, but drive a lot of the complex logic. This example then is never. This means if we're passing alright pal, we're going to end up with never. If we pass in 1, we're going to end up with never.

[1:49] [1: 50] Never is a way of signaling to your types that something should never happen. We're going to break this down in a separate part of the module, and you may indeed have seen it already. This pattern though of returning never allows your conditional types to specify their else logic without having to worry too much about what it is.

[2:11] [2: 11] Really, if we're passing something random in here, and we try to use this never somewhere, then this never is going to throw an error pretty much wherever it's used because it should never happen.