Mapped Types

A mapped type uses the syntax {' '} to loop over every key of an existing type and produce a new type where each property's value, optionality, readonly-ness, or even name is transformed — it is the type-level "for each property" that powers Partial, Readonly, and the rest.

Learn Mapped Types in our free TypeScript course — an interactive lesson with runnable examples, a practice exercise and a quick reference.

Part of the free TypeScript course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

A mapped type is a stamping machine on an assembly line . The original type T is a tray of labelled parts. The machine picks up every part ( K in keyof T ), does the same operation to each — paint it (change the value type), mark it "do-not-touch" ( readonly ), make it optional ( ? ), or relabel it ( as ) — and drops the transformed part into a new tray. You describe the operation once; the machine applies it uniformly to all keys, no matter how many there are.

1. The Mechanism

Every mapped type starts the same way: keyof T gives a union of T 's property names, and iterates over each name K . For the value you almost always use the lookup type T[K] ("the type of property K "). Identity in, identity out — until you change something:

The runnable box performs the same "walk every key and rebuild" over a real object, the way the compiler does at the type level.

2. Key Remapping with as

Since TypeScript 4.1 you can rename keys during the map using as , almost always with a template literal type . This is how you generate getX / setX method names from data fields. Remap a key to never and the property disappears — that is the standard way to filter keys.

3. Modifiers: readonly , ? , and Their Removers

A mapped type can add or strip the readonly and optional ( ? ) modifiers on every property. Prefix a modifier with - to remove it. These four lines are essentially the entire source of TypeScript's Partial , Required , and Readonly :

Modifiers are type-level, but the box below shows their runtime consequence : filling in defaults so no key is missing (the effect of -? ) and freezing an object so it can't be reassigned (the effect of readonly ).

🎯 Your Turn

Build the runtime version of a key-remapping mapped type that turns each field into a setX method. Fill in the blanks and match the expected output.

Implement the runtime form of a key-remapping mapped type that produces a <key>Valid method for every field. Follow the outline, run it, and match the example output.

Practice quiz

What does the mapped type syntax { [K in keyof T]: ... } do?

  • Loops over the values of T
  • Deletes keys from T
  • Loops over every key K of T to build a new type
  • Runs a for loop at runtime

Answer: Loops over every key K of T to build a new type. It is a type-level loop: for each key K in keyof T, define a property.

Inside a mapped type, what is T[K] usually?

  • The lookup type: the type of property K
  • A runtime value
  • Always string
  • The number of keys

Answer: The lookup type: the type of property K. T[K] is a lookup type that keeps each property's original type.

What does the minus sign do in { [K in keyof T]-?: T[K] }?

  • Adds optionality
  • Subtracts a number
  • Makes properties readonly
  • Removes the optional modifier from every property

Answer: Removes the optional modifier from every property. Prefixing a modifier with - removes it; -? strips optional, which is how Required<T> works.

How is Partial<T> defined as a mapped type?

Partial<T> adds the optional modifier: { [P in keyof T]?: T[P] }.

How do you rename keys during a mapped type?

  • With an as clause, usually a template literal type
  • With the rename keyword
  • By assigning to keyof
  • You cannot rename keys

Answer: With an as clause, usually a template literal type. Key remapping uses an as clause with a template literal type to compute each new key name.

How do you filter (drop) a key in a mapped type?

  • Set its value to null
  • Use delete
  • Remap the key to never
  • Set it to undefined

Answer: Remap the key to never. Remapping a key to never omits that property from the result.

Which built-in is a one-line mapped type?

  • console.log
  • Readonly<T>
  • JSON.parse
  • Math.max

Answer: Readonly<T>. Partial, Required, Readonly, and Record are all one-line mapped types in TypeScript's lib.

Why can a template literal key like the capitalized form of K error without constraining K?

  • Capitalize is not real
  • get is reserved
  • Mapped types ban templates
  • K may be string | number | symbol, but template literals need a string

Answer: K may be string | number | symbol, but template literals need a string. Constrain it with Capitalize<string & K> or K & string so the key is a string.

What is the runtime form of a mapped type?

  • A special runtime object
  • There is none; mapped types are compile-time only
  • A frozen array
  • A Proxy

Answer: There is none; mapped types are compile-time only. Mapped types vanish at compile time; to transform real data you write an actual loop.

What does { readonly [K in keyof T]: T[K] } produce?

  • Partial<T>
  • Required<T>
  • Readonly<T>
  • Record<K, V>

Answer: Readonly<T>. Adding readonly to every key is exactly how Readonly<T> is defined.