Mapped types in TypeScript are a powerful feature that allows you to create new types based on existing ones by performing transformations on their properties. They essentially enable you to "map" from one type to another by applying a set of rules. Mapped types are useful when you need to make modifications to an existing type, such as making all properties optional or readonly.
A mapped type is defined using a combination of a type variable, a key ‘in‘ clause, and a mapping expression applied to the properties of the original type. Here’s the basic syntax of a mapped type:
type MappedType<T> = {
[P in keyof T]: /* mapping expression based on T[P] */;
};
Here, ‘P‘ is a type variable that iterates over all keys of the type ‘T‘. ‘keyof T‘ is an index type query, which resolves to a union of all property keys of the type ‘T‘. The mapping expression will be applied to each property value type in ‘T‘, depending on ‘T[P]‘.
Let’s see some examples.
1. **Making all properties of a type optional:**
type Partial<T> = {
[P in keyof T]?: T[P];
};
Now, you can create a new type with all properties optional:
interface Person {
name: string;
age: number;
}
type OptionalPerson = Partial<Person>;
Here, ‘OptionalPerson‘ would have the type ‘ name?: string; age?: number ‘.
2. **Making all properties of a type readonly:**
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
Then, you can create a new type with all properties readonly:
interface Point {
x: number;
y: number;
}
type ReadonlyPoint = Readonly<Point>;
Now, ‘ReadonlyPoint‘ would have the type ‘ readonly x: number; readonly y: number ‘.
3. **Mapping property value types:**
You can also transform the value types of a type, for example, wrapping them in a ‘Promise‘:
type PromiseType<T> = {
[P in keyof T]: Promise<T[P]>;
};
Using the ‘Point‘ type from the previous example:
type PromisePoint = PromiseType<Point>;
In this case, ‘PromisePoint‘ would have the type
‘ x: Promise<number>; y: Promise<number> ‘.
You can use mapped types to create powerful utility types and, as they are generic, they can be reused across your codebase. Various mapped types (like ‘Partial‘ and ‘Readonly‘) are already included in TypeScript’s standard library for your convenience.