TSadvancedts-evergreen

Mapped types

Build types from other types.

A mapped type walks the keys of an existing type and produces a new one β€” the machinery behind Partial, Readonly, and Record, and the place to reach when no built-in utility fits.

The mapping syntax

A mapped type has the shape { [K in Keys]: ValueType }. K is a fresh type variable bound to each member of the union Keys in turn β€” almost always keyof T. Inside the body you can reference K (the current key) and T[K] (the value type at that key). This single construct is how the standard library defines Partial, Readonly, Pick, and Record.

Modifiers: readonly and ?

Each mapped property can carry the readonly and optional (?) modifiers, and you control them with + (add) or - (remove). { readonly [K in keyof T]: T[K] } adds readonly; { -readonly [K in keyof T]: T[K] } strips it. The same applies to ?: [K in keyof T]? makes everything optional, [K in keyof T]-? makes everything required. A bare readonly/? is shorthand for +readonly/+?.

Key remapping with as

{ [K in keyof T as NewKey]: T[K] } lets you rename keys while you map. Combined with template literal types you can prefix keys (`get${Capitalize<...>}`), and by mapping a key to never you can filter it out entirely β€” a key that resolves to never is dropped from the result.

Mapping over a union of keys

The source of keys need not be keyof T. Map over any string-literal union and you get a Record-like object whose keys are fixed at the type level, with a uniform β€” or even key-dependent β€” value type.

Try it 5 examples

Readonly<T> by hand

TSintro
Press Run to execute

The output keys: x,y / values: 3 shows the data survives the mapping intact β€” MyReadonly<T> only adds the readonly modifier, it never touches the runtime shape or values. The compile-time guard (assigning p.x would error) is invisible at runtime, which is exactly why mapped types cost nothing.