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