Mapped Types

Transform every property of a type at once — the engine behind Partial, Readonly, and friends.

A mapped type walks over the keys of an existing type and produces a new property for each. The shape is { [K in keyof T]: ... }.

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

Modifiers you can add or remove

Prefix with + or - to add or strip readonly and ?. -readonly makes a frozen type writable again; -? makes optional properties required — this is literally how Required<T> works.

type Mutable<T> = { -readonly [K in keyof T]: T[K] };
type Concrete<T> = { [K in keyof T]-?: T[K] };

Because T[K] looks up each value type, you can also transform values — wrap them in Promise, make them nullable, and so on.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • A Nullable<T> mapped type adds | null to every property of an interface to represent database nullable columns.
  • An EventHandlers<T> mapped type prefixes every key in T with on to generate a full set of event handler props.
  • A Getters<T> mapped type transforms every property into a getter function type for a proxy or store implementation.

More examples

Build Partial from scratch

Re-implements Partial<T> using a mapped type that iterates every key K and marks it optional with ?.

Example · ts
type MyPartial<T> = {
  [K in keyof T]?: T[K];
};

interface User { id: number; name: string; email: string; }

const patch: MyPartial<User> = { name: 'Bob' }; // only name provided

Nullable mapped type

Maps every property of T to T[K] | null, useful for representing objects that come from nullable database columns.

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

interface Config { host: string; port: number; }

type NullableConfig = Nullable<Config>;
// { host: string | null; port: number | null }

Readonly mapped type

Adds the readonly modifier to every key by prefixing the mapped key clause, reproducing Readonly<T>.

Example · ts
type MyReadonly<T> = {
  readonly [K in keyof T]: T[K];
};

interface Point { x: number; y: number; }

const p: MyReadonly<Point> = { x: 1, y: 2 };
// p.x = 5; // Error: cannot assign to readonly property

Discussion

  • Be the first to comment on this lesson.
Mapped Types — TypeScript | SoundsCode