K extends keyof T in typescript

ref – https://stackoverflow.com/questions/57337598/in-typescript-what-do-extends-keyof-and-in-keyof-mean

Initially methods that return unions such as “string | number” is very limited.
Thus, let’s get away from union types.

Let’ take a look at this example. We create a class Attributes, which will will be initialized with interface type T.

We initialize a sample interface called UserProps.

Thus, we’ll be passing UserProps into Attributes like so:

This means Attributes will be type checking to make sure what we pass into constructor will conform to UserProps.

Now let’s implement get.

keyof T

keyof T is the union of public property names of T.

In our example, we will be using UserProps as type T.
So “keyof T” will produce “name” | “age” | “id”.

K extends keyof T

K extends keyof T is used to constrain our function get function’s param key.
What we’re saying here is that since we’ll be passing in UserProps, “keyof T” will translated to “keyof UserProps”, which then return to us a union of “name” | “age” | “id”.

Then type K of param key must be one of these three. In other words, K can only be “name”, “age”, or “id”.
Note that the “extends” used here has nothing to do inheritance!

T[K]

T[K] is the return type.

Say if we were to pass in “name” into function get,
K will be “name”
T is UserProps,
Then T[K], UserProps[“name] will give the type string.

Now that the code is clear, let’s look at the full source and see how it is used:

We first instantiate an Attributes where it accepts interface UserProps as T. The object we pass in must conform to UserProps with properties name, age, and id.

We then use the instance and call function get with parameter name.

name conforms to keyof UserProps, so K is now name.

Since K is name then T[K] will be string.
We see this by hovering over name and intellisense will show the type string.

For age and id, its returned instances will have type number.

This is a much better way than to return limited unions.