Transcript from the "Type Queries" Lesson
>> Next, we're going to talk about type queries. Type queries are a way that you can extract a type from a value that you might have, and TypeScript offers a couple of these. We're going to look at each of the different kinds of type queries that we can, perform.
[00:00:17] And then we're going to look at an interesting use case called a type registry pattern. Where we'll combine open interfaces with type queries and get some interesting results. So, first, let's look at keyof. The keyof type query allows us to obtain the type representing an object. So in this case, we've got date property names.
>> And symbols, those are the three things.
[00:01:17] So when we say, give me the intersection type of date, property names, and string, we're gonna get the complete set of properties on date that have string keys. We're kind of like excluding the numeric properties and symbol properties, if they may exist. I'm sure there's a symbol property somewhere in there, but that's why we get all of these spelled out so nice, right?.
[00:01:41] Those are all the names of the things you could find on dates. They're method names and field names. And here are the symbols. Doesn't appear, they're already. Typeof, okay. In any case, this is a neat little trick if you ever wanna expand out what something is, just intersect it with string and TypeScript will say, I can't just regard this as key update anymore.
[00:02:11] I have to make it all those strings, question?
>> I think you might have just answered I was like why can't I hover over date property names to see them but you're saying it just it's like a shorthand it VS Code on expand but once you do the intersection, it forces it to
>> There you go, I'm defeating it's convenient and concise representation here. Being a good guy developer, I know better. So I'm saying spell it all out for you. And you see we get 33 more, you're not seeing it all. Let's look at another type query, it's called typeof.
[00:02:50] And I'm just going to uncomment this code here, oops, that is a caps lock. So here we have a function called main (), and we have an API response that comes back. And you can see that I have a fetch, which this function returns a promise that resolves to a response object.
[00:03:17] It's not ultimately the JSON but the HTTP response. It can think of this promise as like, the first byte when the response comes in, and then you could, wait for the last byte and get all the JSON. And then here I've got a promise that is immediately resolved to a string.
[00:03:39] So I've got this API response here, it's tuple, cuz I'm waiting for both promises. I'm kind of racing them against each other, waiting for both to resolve. And I get this tuple response string, but I don't have a type here. Maybe this is more complicated and I don't wanna write it out by hand.
[00:04:02] I want it to just always be, whatever this is, I wanna create a variable that has a matching type. I would use typeof here and look at API response type, its response, string. So it's almost like I'm taking a value and typeof extracts the type of the value.
[00:04:23] Be careful, this is different when you're in type space over here, right? This is the same keyword but used in a very different way compared to. You can kind of think of it I mean, in both cases, we're like inquiring about the type of the thing. But remember, this can only be like the primitive types.
[00:04:55] Well, sorry, it can only be a very small set of strings. Object will come back as a string for anything that's an object. So, this, when used in the context of obtaining a type from a value. This can return a much like higher resolution piece of information, the actual type of whatever this is.
[00:05:16] So don't get these two mixed up, it's the same word. Conceptually, you're still getting a type from a value, but this one's, I think there are only like eight strings that this can return. Whereas this can return any type. Also, this is an interesting place to just point this out, cuz it was convenient to do so.
[00:05:35] This is a type alias defined within a function scope. Up until now, just for convenience, all of our Interfaces and types have been in sort of top level module scope. There's nothing to stop you from creating type aliases or interfaces wherever you'd create variables. You could technically, although it's kind of weird, create a class in here.
[00:05:56] It's unusual, but absolutely possible. Maybe if you have a big outer function scope that emits an inner function object like you're doing functional programming. It might make sense to have type declarations that sort of live within a closure and can influence what you're emitting from that closure. So a common use of typeof here is to obtain the static side of a class.
[00:06:29] So what do we mean by that? So a CSS rule, it's a class, right? Normally we do this. And then we get a CSS rule here and. I've misnamed my variables here, but these are all of the things that are available on a CSS rule. It's a base class, so that's why we only have CSS text in parent rule.
[00:07:29] Which is a name of a project with a very short shelf life, if I've ever heard one. But this is prototypal inheritance, which is what's happening behind the scenes with classes. We're seeing that her, so look what we can do here we can say. Let's call this MyRule.
[00:07:54] const foo = new MyRule(). So this is proof that this is not an interface representing an instance, this is a class and we can obtain its type like this And there it is, typeof MyRule, it gives us the type of this value, not the type of an instance of a class but, the type of the class itself.
[00:08:30] Sometimes we call this the static side of the class. If you've used static fields before or static methods this is the static side of the class, right? Including things like this STYLE_RULE, these are just variables that are hanging off of the class itself, and you can see those here.
[00:08:55] So one more type query we're gonna touch on is indexed access types. These are pretty cool and fairly, the syntax at least for me is pretty easy to understand, I hope it is for you too. Let's say we have an interface called car, we've got our make, model here, and then we've got an RGB color of some sort.
[00:09:16] But let's say we wanted to extract just the color of the car, the type of this thing here. It's not a named type. There's no type alias we have access to, but we can use square bracket notation, passing in the string, representing this property key, and look what we get, red, green, blue.
[00:09:35] Indexed access type, meaning you're accessing within a type using an index, this being the index. You can use this for tuples as well, where you'd pass in a numeric index. And you can see we get real type checking happening here, this is a property that's not on the car, we're getting a type error as we should.
[00:09:58] Here's an example of a double dip, right? Reaching into colour and then getting the property, red, what is the type of red? So you're going here, and then here, and then what's its type? And so we get a string. There's your string. And this is really interesting here, projecting a union type through the index without hovering over this what do you think we might get?
[00:10:30] Any ideas? What would what would make sense?
>> Year? Other ideas? Color or a string. Color or a string so you're both right, you get year or the type of year, but you also get this other type. The way I want you to think about this is it's as if we take each member of the union type projected through the indexed access pathway.
[00:11:11] And then we take all of those results and then union them together. Sometimes this is referred to as projecting a union through an indexed access type. If you pass into property names and then you get back, here's your years type and then here's your colors type. It's pretty cool.
[00:11:38] Okay, yes sir?
>> One question from the chat. Could you clarify the difference between keypf and typeof.
>> Yep, happy to go through that again. Keyof I'm gonna add another example here. All right, so we've got a contact here. And if we wanted to get the names, a type representing all valid names of properties, Like this.
[00:12:27] I want this type, but I don't want to explicitly define it. I want to get it derived somehow from this object. I would have some problems because effectively, I kinda want like object.keys. But I have a value here. I can't really, we'll call this Try1. I can't do this, I can't, I can't do this.
[00:12:57] Contact refers to a value, but it's being used as a type here. This is a value, so, let's replace this with typeof. Well now, I get a type. I get the type of this value. I've taken a value, and I've obtained a type from it. Now if I wanted to put them together.
[00:13:26] Look at that, name and email. So keyof. It's Object.keys() for types And typeof is get me the type of this value.