In TypeScript, mapping types are a powerful feature that enables creating new types from existing ones by transforming properties individually. This operation enhances code flexibility and reusability. The fundamental form of mapping types involves using index signature syntax to dynamically define properties and their types.
Basic Usage of Mapping Types
Here is a simple example demonstrating how to use mapping types:
typescriptinterface Person { name: string; age: number; } // Use mapping types to create a new type where all properties are optional type PartialPerson = { [P in keyof Person]?: Person[P]; } // Use mapping types to convert all properties to read-only type ReadonlyPerson = { [P in keyof Person]: Readonly<Person[P]>; } // Instantiation const person: PartialPerson = { name: "Alice", // age is optional }; const person2: ReadonlyPerson = { name: "Bob", age: 30 }; // person2.name = "Charlie"; // Error: cannot modify read-only property
In this example:
- The
PartialPersontype converts all properties of thePersontype to optional. - The
ReadonlyPersontype converts all properties of thePersontype to read-only.
Advanced Usage of Mapping Types
TypeScript also supports more complex operations, such as filtering properties based on conditions or modifying property types. Here is an example of advanced mapping type usage:
typescripttype FilterByType<T, U> = { [P in keyof T as T[P] extends U ? P : never]: T[P]; }; interface Info { name: string; age: number; hasPet: boolean; } // Filter out all properties of type number from Info type NumbersOnly = FilterByType<Info, number>; const example: NumbersOnly = { age: 25 };
In this advanced usage, the FilterByType mapping type allows filtering properties that match specific types. This approach enables developers to dynamically create types with tailored characteristics based on requirements.
These mapping type usages significantly enhance TypeScript's expressiveness, allowing developers to write more generic and flexible type-safe code.