Constructs
Mapped types
A loop over a union of keys that builds an object type.
What it is
Read { [K in Keys]: Value } as: for every K in this key set, produce a property named K whose type is that expression. Two independent decisions per key — what it is called, via the optional as clause, and what it holds. Partial, Required, Readonly, Pick and Record are each one line of this.
Examples
Stringify<User>→{ id: string; name: string; }Prefixed<User>→{ getId: number; getName: string; }The
asclause renames the key. This is how a mapped type produces names that were not in the input.Filtered<User>→{ name: string; }Renaming a key to
neverremoves it. That is the only way a mapped type can drop a property.
Each resolved type above was printed by TypeScript 6.0.3, not written by hand.
What it does not do
- It cannot remove a key from the value side. Producing
neveras a property *type* leaves the key present and unfillable, which is not the same as absent. - It stops preserving modifiers the moment the key set is computed.
[K in keyof T]is homomorphic and keepsreadonlyand?; add anasclause or union the keys and they are dropped unless you re-add them.
Takeaway
Keys are decided in the key clause and values in the value clause. Most mapped-type bugs are one of those two answers accidentally used for the other.

