CPCODELAB
TypeScript

Mapped Types

11 min read

Mapped Types

A mapped type iterates over the keys of another type and produces a new object type by transforming each property. The syntax uses in keyof inside the type-level {} braces.

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

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

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

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

type NullableUser = Nullable<User>;
// { id: number | null; name: string | null; email: string | null }

Remapping keys with `as`

TypeScript 4.1 introduced key remapping via as. You can rename keys in the output type using template literal types.

ts
type Getters<T> = {
  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};

type UserGetters = Getters<User>;
// { getId: () => number; getName: () => string; getEmail: () => string }

// Filter out keys by remapping to never
type OmitFunctions<T> = {
  [K in keyof T as T[K] extends Function ? never : K]: T[K];
};

The built-in utility types Partial, Required, Readonly, and Record are all implemented as mapped types under the hood. Writing your own mapped types is the key skill for building reusable type-level abstractions.

Ready to test yourself?
Practice TypeScript— quiz & coding exercises