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.