Mapped types in TypeScript allow you to create new types by transforming existing ones. They are particularly useful for creating types that are variations of other types, such as making all properties optional or readonly. This topic will cover the basics of mapped types, provide practical examples, and include exercises to reinforce the concepts.
Key Concepts
- Definition: Mapped types use a syntax that iterates over the properties of an existing type and applies a transformation to each property.
- Syntax: The basic syntax for a mapped type is:
type MappedType<T> = { [P in keyof T]: Transformation; };
- Common Use Cases:
- Making all properties optional
- Making all properties readonly
- Transforming property types
Practical Examples
Example 1: Making All Properties Optional
Let's start with a simple example where we make all properties of a type optional.
type Person = { name: string; age: number; address: string; }; type OptionalPerson = { [P in keyof Person]?: Person[P]; }; // Usage const person1: OptionalPerson = {}; // Valid const person2: OptionalPerson = { name: "Alice" }; // Valid
Example 2: Making All Properties Readonly
In this example, we will create a mapped type that makes all properties of a type readonly.
type ReadonlyPerson = { [P in keyof Person]: Readonly<Person[P]>; }; // Usage const person3: ReadonlyPerson = { name: "Bob", age: 30, address: "123 Main St" }; // person3.name = "Charlie"; // Error: Cannot assign to 'name' because it is a read-only property.
Example 3: Transforming Property Types
Here, we will create a mapped type that transforms all properties to a different type.
type StringifiedPerson = { [P in keyof Person]: string; }; // Usage const person4: StringifiedPerson = { name: "Dave", age: "40", address: "456 Elm St" };
Exercises
Exercise 1: Create a Mapped Type to Make Properties Nullable
Create a mapped type Nullable<T>
that makes all properties of a type T
nullable.
type Nullable<T> = { [P in keyof T]: T[P] | null; }; // Test it with the Person type type NullablePerson = Nullable<Person>; // Usage const person5: NullablePerson = { name: null, age: 25, address: null };
Exercise 2: Create a Mapped Type to Add a Prefix to Property Names
Create a mapped type Prefixed<T, Prefix>
that adds a prefix to all property names of a type T
.
type Prefixed<T, Prefix extends string> = { [P in keyof T as `${Prefix}${P & string}`]: T[P]; }; // Test it with the Person type type PrefixedPerson = Prefixed<Person, "prefix_">; // Usage const person6: PrefixedPerson = { prefix_name: "Eve", prefix_age: 35, prefix_address: "789 Pine St" };
Common Mistakes and Tips
- Forgetting to use
keyof
: When creating mapped types, always ensure you usekeyof
to iterate over the keys of the type. - Incorrect transformations: Ensure that the transformations applied to the properties are valid and make sense for the use case.
- Complex transformations: For more complex transformations, consider breaking them down into smaller, more manageable mapped types.
Conclusion
Mapped types are a powerful feature in TypeScript that allow you to create new types by transforming existing ones. They are particularly useful for creating variations of types, such as making properties optional, readonly, or transforming their types. By understanding and utilizing mapped types, you can write more flexible and reusable TypeScript code.
In the next topic, we will explore Conditional Types, which allow you to create types based on conditions, further enhancing the flexibility and power of TypeScript's type system.
TypeScript Course
Module 1: Introduction to TypeScript
- What is TypeScript?
- Setting Up the TypeScript Environment
- Basic Types
- Type Annotations
- Compiling TypeScript
Module 2: Working with Types
Module 3: Advanced Types
Module 4: Functions and Modules
Module 5: Asynchronous Programming
Module 6: Tooling and Best Practices
- Linting and Formatting
- Testing TypeScript Code
- TypeScript with Webpack
- TypeScript with React
- Best Practices