Exclude null and undefined from the Maybe Type
This challenge might have been a little bit of a mind-bender.
The solution is to find a type that can act as a constraint that is not
undefined, but also can represent anything.
We could consider adding
extends and listing several types:
0:00 This one may have been a bit of a mind-bender. It certainly is when you first see it. The solution here is to basically say we want to find a type which can act as a constraint, which is not or undefined but also represents basically anything.
0:18 We can think about doing this by saying it's either going to be a string, or it's going to be a boolean or -- I don't know -- let's say a number, for instance. That will make everything pass. We can remove one of these constraints. Then this will start erroring, for instance.
0:35 Really, we want this Maybe type to accept anything. We want it to be able to say Maybe pass in some crazy random object, wow 1. This currently will fail too.
0:47 How do we do a reverse constraint here? A trick you can use for this is to say, "T extends" an empty object. This value has a specific use in TypeScript. What it does is it says this is going to represent anything that's not or undefined.
1:07 You'll notice it's different from saying this is like a truthy thing. We can pass to this. We can pass zero to this. Why is this possible? Let's say we have a const whatever. We're going to say it's an empty object. We can actually assign anything to this. We can say, "1, blah, blah, blah, blah, blah, blah, blah, blah." We can't assign it or undefined though.
1:33 Why is this? The reason is that basically TypeScript does structural comparisons when it checks that things are assignable to each other. If you have an empty object, what we're basically saying...Let's say that we have a...I don't know. Let's say, "T extends wow boolean" here. This is going to break a lot of stuff.
1:54 Let's say we have type Example = Maybe. We have to pass wow. It can be 1 or , so let's say boolean. We can add other things to do this. We can say, "nice 1," for instance. Now our example is going to be wow boolean, nice 1.
2:13 TypeScript is doing a structural comparison here. It doesn't actually care about exclusive properties or things like this. It's basically saying, "Does it match this contract? I don't mind what else it passes in. Does it match here?"
2:29 Now if I remove wow boolean, then we're going to get the same thing because, of course, if I remove this here too, this object is assignable to this object. Why is string assignable to an empty object, for instance? In TypeScript, string is just an object. It's just an object with various methods associated with it.
3:16 Even though you have a falsy value here, a value is still an object. This is a really, really key part of understanding the fundamental bits of TypeScript. Everything is an object. You can use an empty object to represent anything that isn't or undefined.