TypeScript Mapped Types


Mapped types in TypeScript allow you to create new types based on existing ones by iterating over their properties and applying a transformation. They provide a concise way to manipulate and transform type definitions, reducing boilerplate and improving code maintainability.

Let’s explore how mapped types work and how they can be useful.

Basic Usage

Consider an interface representing a user:

interface User {
  firstName: string;
  lastName: string;
  age: number;
  isActive: boolean;
}

Suppose you need a new type that represents the same user data but with all properties made optional. You could manually create a new interface, but mapped types offer a more elegant solution:

type PartialUser = {
  [P in keyof User]?: User[P];
};

Let’s break down this code:

Built-in Mapped Types

TypeScript provides several handy built-in mapped types:

Using the built-in Partial would simplify our previous example:

type PartialUser = Partial<User>;

Transforming Property Types

Mapped types can also transform property types. Let’s say you want a type where all string properties of User are converted to uppercase:

type UppercaseUser = {
  [P in keyof User]: User[P] extends string ? Uppercase<User[P]> : User[P];
};

Here, we use a conditional type to check if the property type User[P] extends string. If it does, we apply Uppercase<User[P]> to convert it to uppercase. Otherwise, the original property type is retained.

Practical Application

Mapped types are particularly useful when working with forms, data transformations, and creating utility types. For instance, you can use them to define types for API responses, create types for form inputs with validation, or easily transform data between different formats.

By mastering mapped types, you can write more concise, type-safe, and maintainable TypeScript code. They provide powerful tools for manipulating and transforming types, reducing boilerplate, and improving the overall structure of your projects.