Intermediate TypeScript Type Queries
Transcript from the "Type Queries" Lesson
>> Type queries allow us to obtain a type from a value. And there are two new keywords I want to introduce, which fit into the category of type queries. Those are keyof and typeof. So first, we're going to look at keyof. keyof allows us to obtain all of the keys of an interface or object type of some sort.
[00:00:30] So here, note that we're looking at a type alias, right? And if we hover over Date here, you see obviously the word interface Date. That's an indication that we're working with this as a type. And we're using this keyof operator, and then we're getting something here, it says DatePropertyNames.
[00:01:22] Remember, if we think about the Venn diagram, the intersection type operator will help us to select only those things that are in the overlap portion of the Venn diagram, right? We're saying you must be a key of date and you also must be a string. And if you meet condition one and condition two, then you're part of this new type.
[00:01:46] If you think about geometry, and I'm sort of revealing my educational background here. I'm a mechanical engineer by education. I think of this kind of like a dot product in that, if you remember that you can kind of define vectors as some portion in the x direction and some portion in the y direction.
[00:02:05] You're kind of getting the part of a type that aligns with some other type, kind of like a dot product. That's useful enough to me that I want all of the other sort of visual learners to think of it that way. So it's the sub-part of keyof Date that is also included with string.
[00:02:30] So here we've got the same line that we had above. In our second line, we're saying intersect this with string, and look what we get. We get all of the property names of date that are also string. We've got toDateString, toLocaleTimeString, getFullYear, 33 more, right? It's even truncating this tooltip.
[00:02:56] There's a lot going on here. So remember, we're still working with types, but what we've created here is a union type, right? This is the or concept of all of the different property names, which could include methods or fields that we could find on date. We've obtained type information here.
[00:03:17] So if we wanted to get the other things that are left over, apparently there's this Symbol.toPrimitive thing. And you can read more about that here, but that's why this didn't show us a list of strings. There's actually one symbol in there and it's for converting a date to either a number or a string.
[00:03:38] And there's a footnote if you wanna play with that, if you're curious and wanna pull that thread. So that's keyof. It's gonna be really important later in the course, keyof. typeof, so this is a much more direct type query in that we're literally saying, I have a value and I wish to get the type that describes this value.
[00:04:03] So here's a little bit of sample code. I've made sort of a non-trivial value here just to sort of make things interesting. We have a fetch which returns a promise that resolves to a response, right? Look at that return type, they're promise, and then generic over response. And then here, we've created a second promise that resolves to a string.
[00:04:28] Promise.all, it takes an array of things. Any of those that are promise-ish, it'll wait for those. So if we await this, look at that tooltip, it's a tuple containing a response and a string. But let's pretend that this was much more complicated. We don't have a nice type that describes this.
[00:04:49] So if we wanted to obtain that type, all we'd need to do is grab this, right? This is our value. See the word const in the tooltip? We're using this typeof operator, or this keyword rather. And then we can create a type alias that describes what this thing is.
[00:05:10] You may be wondering like, where might I use this? Well, what if you're consuming a library that exposes some things to you, some values? But they don't give you the type information for these things directly as an interface or as a type alias that you could independently import and export.
[00:05:31] But if you wanted to make a function that takes the return value of something else or a function. What if this were a webpack config, a really complicated, big, big object with lots of stuff on it? If you wanted to make a function that takes a webpack config as an argument, this would be a way where you could say, hey, look, I have this thing.
[00:05:50] Maybe it came out of a function as a return value. And now I can have a type for it, and I can use that type for something else. It's great for sort of threading concepts through and making sure you're still referring to the original source of truth. I don't have a tuple written in this piece of code at all.
[00:06:07] I mean, unless you would argue that this is a tuple, but certainly not a tuple type. This is a value, right? It's the thing passed into Promise.all. But I am very much referring to the type information for resolve, for fetch, for Promise.all. That's all baked in to this Response, string.
[00:06:29] So if these were to ever change, if I upgrade my typescript version, for example, everything will flow through very nicely. I'm still just pointing to one single source of truth. I'm just sort of giving it a name so I can hold on to it with this type query.
[00:06:44] So typeof is also useful for obtaining the static side of a class. By static side, we mean like the factory, right? It's the ability to create new fruit in this case and any static methods that are on this class. So if we look at the tooltips below here, we haven't written the word typeof, but we can see it appearing to us.
[00:07:11] If we store as a variable a copy of this Fruit class, not an instance, we can see the type of this variable is typeof Fruit. And then if we create an instance, we can see that the type is just Fruit. So if you wanted to see the static stuff available on a class and you wanted a type for that, remember, if we just use Fruit in the value position as we are here, we're referring to the constructor, right, the class, not an instance.
[00:07:48] And then if we look at what its type is, now we have a way of getting access to it using this type query.