How to Use Mapped Types in TypeScript

Use mapped types in TypeScript when you need to transform every property of an existing object type in a consistent way. They are perfect for update payloads, readonly models, nullable transforms, and reusable library utilities.

What you’ll build or solve

You’ll learn how to use mapped types in TypeScript to transform object properties with keyof, modifiers, and custom value rules. You’ll also know when mapped types are cleaner than rewriting shapes manually.

When this approach works best

This approach is the right choice when multiple properties should follow the same type rule.

Common real-world scenarios include:

  • Partial update payloads
  • Readonly configs
  • Nullable form states
  • API response transforms
  • Feature flag models

This is a bad idea when the target type is tiny and rewriting it manually is clearer.

Prerequisites

You only need:

  • Strong TypeScript object type knowledge
  • keyof
  • Generics
  • Utility type familiarity

Step-by-step instructions

Step 1: Create a basic mapped type

The core syntax loops over keys.

type Stringify<T> = {
  [K in keyof T]: string;
};

This converts every property value into string.

type User = {
  id: number;
  active: boolean;
};

type UserStrings = Stringify<User>;

The result becomes:

{
  id: string;
  active: string;
}

Step 2: Make every property optional

Mapped types are great for update payloads.

type Optional<T> = {
  [K in keyof T]?: T[K];
};

This works like the built-in Partial<T>.

It is ideal for patch APIs and forms.

Step 3: Make every property readonly

Use readonly modifiers.

type ReadonlyFields<T> = {
  readonly [K in keyof T]: T[K];
};

This protects configuration objects and immutable state.

Step 4: Combine custom transforms

Mapped types can transform values too.

type Nullable<T> = {
  [K in keyof T]: T[K] | null;
};

This is excellent for form-reset states.

What to look for:

  • Use [K in keyof T]
  • Great for property-wide transforms
  • Add ? for optional fields
  • Add readonly for immutability
  • Great for reusable object utilities

Examples you can copy

Optional update payload

type Patch<T> = {
  [K in keyof T]?: T[K];
};

Readonly config

type Frozen<T> = {
  readonly [K in keyof T]: T[K];
};

Nullable form

type Resettable<T> = {
  [K in keyof T]: T[K] | null;
};

Common mistakes and how to fix them

Mistake 1: Using mapped types for tiny one-off objects

What the reader might do:

Create a generic mapped helper for a 2-field local object.

Why it breaks: the abstraction adds noise.

Corrected approach:

Write the object shape directly.

Mistake 2: Forgetting to preserve original property values

What the reader might do:

[K in keyof T]: string

when the original type should remain.

Why it breaks: values lose original typing.

Corrected approach:

Use T[K] when preserving the type.

Mistake 3: Over-nesting mapped utilities

What the reader might do:

Layer many transforms into one unreadable helper.

Why it breaks: maintenance suffers.

Corrected approach:

Compose smaller named mapped types.

Troubleshooting

If values lose their original type, use T[K].

If updates need optional fields, add ?.

If state must stay immutable, add readonly.

If the utility becomes unreadable, split it.

Quick recap

  • Use [K in keyof T] for mapped types
  • Great for object-wide transforms
  • Add ? for optional properties
  • Add readonly for immutable models
  • Keep helpers small and reusable