If you already have a subscription, you can sign in.
Enjoy free content straight from your inbox 💌
00:00
Here we have a type representing a person with member's name and location of type string and age of type number. We have an example of such a person in the form of John age 35 living in Melbourne. We have a utility function that lets us access any member of John along with logging out a statement to the console. As an example, we can use this method to get John's age. Now an issue with the signature of our log function is that it allows any old string key to be passed in. For example, we can pass in a key
00:33
that is not present on the John object like email. Now we can improve the situation by replacing our open-ended string with a limited set of string literals using a string literal union, for example, we can say that key must be name, age, or location, which are the only valid keys for the person type. And now type strip correctly highlights invalid access as an error. However, this list of keys is essentially code duplication that will have to be maintained as we continue to work on the person type.
01:05
Fortunately, this is something that can be automated with the TypeScript key of type operator. The key of type operator takes a type as input and returns a union of the keys from that type. And this is exactly the union of the strings that we wanted. So we can replace our hand coded union of string littles with a simple key of query on the person type. And because we are restricting the keys to be from the person type, we'll annotate the obs to be of type person as well. Now notice that our log GA function doesn't have any code specific to the person type
01:39
to make this function more general. We can use generics using a generic type for the ops and a generic type for the key. And now the requirement that key must be something that is in the key of obs can be enforced by a generic constraint when we define the generic argument. Now with this generic constraint, TypeScript knows that key will be something that is in the key of orbit. So when we try to index OB with key in our JavaScript code, TypeScript correctly infers the type of the return value to be an index lookup type OB key.
02:13
And since value is what we return from the log function, the return type of the function is also inferred to be the lookup type OB key. Now with this function signature in place when obs is of type person and key is of type age, the return type will be the lookup person age and we can see that it needs to be a number. And indeed that is what is automatically inferred when we try to use log to get Jones age. And now we can get rid of the invalid access for the email property.
02:46
Now, similar to how we have the log function, we can easily apply the same knowledge to build a log set function. The body of the function is pretty simple in terms of the function's signature. It is very similar To the signature of the log get function. The only difference is that the log set function takes an additional third argument, which has been annotated with a lookup type object key. And we've seen this type before as well. This is exactly the return type of the log get function. And now we get a nice utility function that can be used to set any value on a member of any type.
03:20
And if you make any city mistakes, for example, misspell a property or provide an invalid type for that particular property, we get a nice compiler error from TypeScript. Now the key of operator by itself is quite simple. It simply returns the union of strings of keys of any given type. Here we've combined the key of operator with other features in TypeScript, which are generics, generic constraints, as well as with lookup types to provide type safety for something that can be used to observe any given object.