How to Use the keyof Operator in TypeScript
-
Use the
keyof
Operator in TypeScript -
Use the
keyof
Operator With Generics in TypeScript -
Use the
keyof
Operator for Mapped Types in TypeScript -
Use the
keyof
Operator to Extract Keys From Enums With thetypeof
Operator in TypeScript -
Use the
keyof
Operator to Define Getters in TypeScript - Conclusion
This tutorial demonstrates how to use the keyof
operator in TypeScript.
In TypeScript, there are two types, user-defined and primitive, like number, boolean, and string.
The user-defined types are usually a combination of primitive types in an object. It can be an object representing nested or simple key-value pairs.
Use the keyof
Operator in TypeScript
We can use the keyof
operator to extract the public property names of a type as a union. It is a vital operator and is widely used in writing generics and reusing existing types.
Example:
interface Person {
name : string;
age : number ;
}
type PersonType = keyof Person;
const AgeAttribute : PersonType = 'age'
const NameAttribute : PersonType = 'name';
The above is a simple example of how we can use the keyof
operator to extract the keys from a user-defined type in TypeScript.
The keyof
operator returns all the keys of a type as a string union of types. It can also find the keys passed on to the primitive types.
type PrimitiveNumberKeys = keyof number;
// "toString" | "toFixed" | "toExponential" | "toPrecision" | "valueOf" | "toLocaleString"
Although the keyof
operator may not be convenient for primitive types, we can still apply it to primitive and user-defined types.
Use the keyof
Operator With Generics in TypeScript
TypeScript generics are essential for making widely acceptable function definitions and types.
The keyof
operator can add some constraints to the freedom of a function generics. The following code segment explains how we can achieve this.
interface Person {
name : string;
age : number ;
}
function getWitcherAttribute<T, K extends keyof T>( person : T, key : K) : T[K] {
return person[key];
}
const witcher : Person = {
name : 'Geralt',
age : 95
}
console.log(getWitcherAttribute(witcher, 'name'));
Output:
"Geralt"
This keyof
operator can be used as a getter for objects of the type defined by the user.
K extends keyof T
restricts the keys assigned to K
to only keys in the type T
. The T[k]
returns the same type as in the type T
.
Use the keyof
Operator for Mapped Types in TypeScript
We have already seen how the keyof
operator can use the extends
keyword to constrain certain types in generics.
We can further use generics as mapped types using the in
keyword.
The following is an implementation of the Partial
type in TypeScript.
The Partial
type is used for making all fields of a type optional in TypeScript. We implement it using the ?
operator, making the keys optional.
interface Person {
name : string;
age : number ;
}
type Optional<T> = {
[K in keyof T]? : T[K]
}
const witcher : Optional<Person> = {
name : "Witcher"
}
Similarly, we can implement the Omit
and Pick
types in TypeScript.
type PickType<T, K extends keyof T> = {
[P in K] : T[P]
}
type OmitType<T, K extends keyof T> = PickType<T, Exclude<keyof T, K>>
const witcherWithoutAge : OmitType<Person, 'age'> = {
name : "Geralt"
};
const witcherWithOnlyAge : PickType<Person, 'age'> = {
age : 95,
}
The types are defined as PickType
and OmitType
to avoid duplications with the original Pick
and Omit
types. These are the actual implementations of the Pick
and Omit
in TypeScript using the keyof
operator.
Use the keyof
Operator to Extract Keys From Enums With the typeof
Operator in TypeScript
The keyof
operator can also extract the keys from an enum
.
Example:
enum Colors {
Yellow,
Red,
Black,
Blue,
Green
}
type ColorType = typeof Colors;
type AllColors = keyof ColorType;
// "Yellow" | "Red" | "Black" | "Blue" | "Green"
// it can be also be written together
type AllColors = keyof typeof Colors
This operator is very convenient and can be used to further create the Record
type.
Suppose a map is created mapping the colorType
to a log message of type string. It can be implemented using the Record
type.
Example:
type LogColorMap = Record<AllColors, string>
const LogLevel : LogColorMap = {
Black : "Normal",
Blue : "Info",
Green : "Success",
Red : "Danger",
Yellow : "Warning"
}
Thus, the enum is used to create another type efficiently using the keyof
operator.
Use the keyof
Operator to Define Getters in TypeScript
We can use the keyof
operator to create getters for a type. We use the concept of mapped types and capitalize the keys using the Capitalize
type.
Example:
interface Person {
name : string;
age : number ;
}
type Getters<T> = {
[P in keyof T as `get${Capitalize<string & P>}`] : () => T[P];
}
class PersonCls implements Person, Getters<Person> {
age;
name;
constructor(){
this.age = 95;
this.name = "Geralt";
}
getName = () => {
return this.name;
}
getAge = () => {
return this.age;
}
}
const witcher = new PersonCls();
console.log(witcher.getName())
Output:
"Geralt"
Conclusion
Thus, the keyof
operator has various use cases and is specially used when creating a library with many generic types. Moreover, it is also used to extract types from existing types and create new ones.