Mapped types
| Map over keys | |
| Add or remove ? | |
| Readonly maps | |
| Partial from scratch |
Map over keys
A mapped type builds a new object type by looping over the keys of an old one. The in keyword walks each key while keyof collects them.
Toggles turns every flag into a boolean switch. Add a key to Flags and the mapped type follows it at once.
type Flags = {
dark: boolean;
wide: boolean;
};
type Toggles<T> = {
[K in keyof T]: boolean;
};
type FlagToggles = Toggles<Flags>;
Add or remove ?
A question mark after the key list makes every property optional. The same spot also accepts a minus sign to strip optionality back off.
Optional needs no fields at all, which is handy for forms and patch objects. The value for each key stays exactly as it was.
type Optional<T> = {
[K in keyof T]?: T[K];
};
type Draft = Optional<Flags>;
const empty: Draft = {};
Readonly maps
The readonly modifier works in the same key position and freezes every property. Frozen objects can be read but never reassigned.
origin reads fine, yet writing to origin.x fails at compile time. Use this shape for config and shared constants.
type Frozen<T> = {
readonly [K in keyof T]: T[K];
};
type Point = { x: number; y: number };
const origin: Frozen<Point> = { x: 0, y: 0 };
Partial from scratch
The built-in Partial is just this pattern with a friendlier name. MyPartial maps each key to itself plus undefined and marks it optional.
Reading the hand-written version first makes every utility type later feel obvious. The next lessons put them all to work.
type MyPartial<T> = {
[K in keyof T]?: T[K] | undefined;
};
type HalfPoint = MyPartial<Point>;
const half: HalfPoint = { x: 1 };
Next: Conditional types
Article author: Arthur Isaev