The Empty Object Type
Before we solve this challenge, let's talk about TypeScript's hierarchy of types.
Sitting at the top of this tree is the unknown
type that can accept all other types.
Rooted at the very bottom of the tree, is the never
type. Unlike unknown
, never
is the type to which no other type can be
Transcript
00:00 Let's start actually in diagram land here. We know that in TypeScript, at the very top of the type tree is unknown. Unknown is the type that all types can be passed to. And at the very bottom is the type of never. Never is the type that no types can be passed to, but can be passed to all other types.
00:20 And so in the middle, then, we can imagine like an object with a string on it here, which never can be passed to. And that then can be passed to, let's say, an empty object. And you might think, well, why doesn't TypeScript do kind of exact comparisons here? Well, we'll get to that a bit later.
00:37 But if you can imagine this, if a type just expected like an empty object with no properties on it, then if you passed an extra property to it, then it wouldn't really matter too much. And so if you think about it, type A string is assignable, can be passed to an empty object type. Let's widen this out a little bit, though.
00:56 Let's imagine, then, that we have A string, and then we could also probably pass a string to this empty object. Because this empty object, it doesn't actually, like, there's no stuff on it. So it doesn't matter if we pass something like a string to it, which sure has some extra properties, like some methods and things. And same with a number, with a Boolean.
01:15 Sure, they have like a toString and various sort of like toFixed and toExponential on a number. If we pass a function to it as well, technically, because you can assign properties to a function in JavaScript, this would be assignable to it too. And a symbol would also be assignable to it.
01:33 In fact, if we think about this even more, an empty object can actually represent anything in JavaScript and TypeScript that isn't null or undefined. And so if you imagine never at the bottom of all of this as well, never is assignable to everything. But also an empty object could be passed to unknown.
01:51 So in TypeScript, what they've kind of figured out is that there are three kind of like second level types at the top level. You have unknown, which is the actual proper top type, but then unknown is basically like a union between an empty object, null or undefined.
02:08 How crazy is that? So null and undefined are obviously not assignable to each other, but they can be passed to unknown. And anything else in the language basically fits under this category is an empty object.
02:21 This means then if we go back to our solution here, we can use this type annotation, the empty object, to represent anything that isn't null or undefined. And if we just look at this again and we say, OK, if we just give it like a string or a number, we could like we could technically create a union big enough that we could handle all of these cases.
02:41 Or we could just say this is an empty object and you can pass anything to it. And if we just unsuppress the errors, then we can see arguments of type null is not assignable to parameter of type empty object.
02:53 So this is a really interesting quirk of TypeScript and it has some other kind of consequences that we'll explore later in this section.