Mapped types

Create a new object type by transforming every key of another type.

On this page

Example

#
TypeScript
type Nullable<T> = { [K in keyof T]: T[K] | null }
type Flags<T> = { [K in keyof T]: boolean }

interface Profile {
  name: string
  bio: string
  avatar: string
}

const draft: Nullable<Profile> = { name: 'Emma', bio: null, avatar: null }
const filled: Flags<Profile> = { name: true, bio: false, avatar: false }

const done = Object.values(filled).filter(Boolean).length
console.log(draft.name, `${done}/3 fields`)
Result
Emma 1/3 fields

Definition and usage

#

A mapped type iterates over the keys of a type and creates a new field for each one: { [K in keyof T]: T[K] | null } turns every field of T into a field that can also be null.

While mapping, you can add and remove modifiers: you add readonly and ?, and remove them with -readonly and -?. That’s how Partial, Required, and Readonly are built.

Since TypeScript 4.1, you can also rename keys with as, for example turning fields into getter names: [K in keyof T as `get${Capitalize<K & string>}`].

Syntax

#
Syntax
type New<T> = { [K in keyof T]: NewFieldType }

More examples

#
Renaming keys with as
TypeScript
type Getters<T> = {
  [K in keyof T as `get${Capitalize<K & string>}`]: () => T[K]
}

type LevelGetters = Getters<{ level: number; name: string }>
// type LevelGetters = { getLevel: () => number; getName: () => string }

Good practices

#
  • Before writing your own mapped type, check the built-in Partial, Required, Readonly, Record, and Pick.
  • The -? and -readonly modifiers let you remove optionality and read-only status.

Related entries

#

Spotted a mistake or missing an example? Write to us.