What are Mapped Types in TypeScript?

Hemanta Sundaray

Published December 25, 2023


Mapped types in TypeScript allow you to create new types based on existing ones by applying a transformation to each property of the original type. This can be particularly useful for creating variations of existing types, such as making all properties optional, readonly, or of a different type.

Let's consider an example to see this in action.

First, let's define a Person type with three keys:

type Person = {
  name: string;
  age: number;
  hasPets: boolean;
};

Now, let's create different mapped types based on this Person type.

Example 1 - Making Properties Optional

We'll start by creating a mapped type where each property of Person is optional:

type OptionalPersonType = {
  [Key in keyof Person]?: Person[Key];
};

In this example, OptionalPersonType is a mapped type where each property of the Person type is made optional. This is achieved by using the [Key in keyof Person]? syntax, which iterates over each property (Key) in Person and adds a ? to make it optional. As a result, all properties in OptionalPersonType (name, age, hasPets) are now optional.

Example 2 - Making Properties Read-Only

Next, we'll create a mapped type where every property of Person is read-only:

type ReadOnlyPersonType = {
  readonly [Key in keyof Person]: Person[Key];
};

In this second example, ReadOnlyPersonType is a mapped type where every property of the Person type is made read-only. This is accomplished using the readonly [Key in keyof Person] syntax, which makes each property in the resulting type immutable after their initial assignment. In ReadOnlyPersonType, properties name, age, and hasPets cannot be reassigned once they are set.

Note

In both the examples above, you can see the use of the keyof operator. It is used to extract the keys of a given type as a union of string literals. For instance, when applied to a type like Person, keyof Person would produce a union of the literal types of its keys, such as 'name' | 'age' | 'hasPets'.

Note that TypeScript provides several built-in mapped types, known as utility types, for common operations. For example, Partial<T>, Readonly<T>, and Record<K, T> are all implemented using mapped types.