Stop 07 · TypeScriptTopics · 9/12

Mapped Types

Part of the Frontend Developer Roadmap

In short

Ever wondered how Partial and Readonly actually work? They're mapped types: a loop that runs over every key of a type and changes each one.

Types that programmatically transform every property of an existing type (e.g. making them all optional or readonly) using a `[K in keyof T]` syntax.

The jaadu mascot feeds a certificate template into a printer as matching certificates come out.

Think of it like this

Mail merge for certificates

You have one certificate template and a list of names. Mail merge runs through each name and prints a certificate. A mapped type runs through each key of a type and produces a new property for it, following your template.

Watch it happen

Flags<Profile>, key by key

name
0
email
1
city
2

1/5keyof Profile gives the keys "name" | "email" | "city". [K in keyof T] will visit each one.

The big ideas

What you need to know

Loop over keys

[K in keyof T] goes through every property name of T, one by one.

Change each property

Add ?, readonly or a new value type. T[K] means 'the original type of this key'.

Rename keys with as

as lets you rename keys, for example turning name into getName.

Built-ins use this

Partial, Required, Readonly and Record are all mapped types under the hood.

See it in code

Walk through the code

ts
1type MyPartial<T> = { [K in keyof T]?: T[K] };2 3type Flags<T> = { [K in keyof T]: boolean };4 5interface Profile { name: string; email: string; city: string }6 7type Touched = Flags<Profile>;8// { name: boolean; email: boolean; city: boolean }9 10type Getters<T> = {11  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];12};13type ProfileGetters = Getters<Profile>;14// { getName: () => string; getEmail: () => string; getCity: () => string }

1/4Your own Partial: visit every key, add ?, and keep the original type T[K].

Touched is perfect for form state: one boolean per field, and it updates itself if Profile gets a new field.

Save yourself the pain

Common mistakes

Oops

Writing a mapped type when a built-in like Partial or Record already does it.

Do this instead

Check the utility types first. Write your own only when none fit.

Oops

Getting lost in a huge mapped type nobody can read.

Do this instead

Split it into small named types, and leave a comment showing an example result.

Your mission

Rebuild the built-ins

~20 min

Quick check

What does type X<T> = { [K in keyof T]: string } do to { age: number; name: string }?

Go deeper

  1. 1Write a simple mapped type that makes every property of an interface optional.
  2. 2Compare your hand-written version to the built-in `Partial<T>` utility.
  3. 3Learn key remapping (`as`) for renaming properties in a mapped type.

More topics at this stop

Stuck on this topic? Ask an Insider

Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.

Download
InsideEdge