In TypeScript, some types are defined using extends keyof
or in keyof
. I have tried to understand what they mean, but so far I didn't succeed.
What I got is that keyof
alone returns a union type which has all the names as possible values that are existent as property names on the type that you specify after keyof
.
type T = keyof string;
T
therefor is equivalent to startsWith | endsWith | trim | substring | ...
.
Is this correct?
Now, if I try to think about what extends keyof
and in keyof
mean, my gut feeling says the following:
extends keyof
is any type that derives from T
, i.e. it has all these possible values, but maybe more.in keyof
is any type that takes values from T
, but not necessarily all of them (it's possible, but maybe less).So, from this POV extends keyof
would describe a >=
relation, in keyof
would describe a <=
relation. Is this correct? If not, what would be correct?
keyof is a keyword in TypeScript which is used to extract the key type from an object type.
keyof typeof will infer the type of a javascript object and return a type that is the union of its keys. Because it can infer the exact value of the keys it can return a union of their literal types instead of just returning "string".
What does ?: mean in TypeScript? Using a question mark followed by a colon ( ?: ) means a property is optional. That said, a property can either have a value based on the type defined or its value can be undefined .
For any type T
, keyof T
is the union of known, public property names of T
.
Example:
interface Person { age: number; name: string; } type PersonKeys = keyof Person; // "age" | "name"
Your assumption that keyof string
yields startsWith | endsWith | trim | ...
is therefore correct. You can learn more about it in the lookup type release notes.
extends
, in this case, is used to constrain the type of a generic parameter. Example:
<T, K extends keyof T>
K
can therefor only be a public property name of T
. It has nothing to do with extending a type or inheritance, contrary to extending interfaces.
A usage of extends keyof
could be the following:
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; } const person: Person = { age: 22, name: "Tobias", }; // name is a property of person // --> no error const name = getProperty(person, "name"); // gender is not a property of person // --> error const gender = getProperty(person, "gender");
Aside from the documentation on index types, I found this helpful article.
in
is used when we're defining an index signature that we want to type with a union of string, number or symbol literals. In combination with keyof
we can use it to create a so called mapped type, which re-maps all properties of the original type.
A usage of in keyof
could be the following:
type Optional<T> = { [K in keyof T]?: T[K] }; const person: Optional<Person> = { name: "Tobias" // notice how I do not have to specify an age, // since age's type is now mapped from 'number' to 'number?' // and therefore becomes optional };
Aside from the documentation on mapped types, I once again found this helpful article.
Fun fact: The
Optional<T>
type we've just built has the same signature as the officialPartial<T>
utility type!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With