"Mapped types are type-level loops. Iterate over keys, produce a new shape."
The mapped-type syntax
{ [K in keyof T]: NewType } creates a new object type by iterating over T's keys. For each key K, the property's value type is whatever expression you write after the colon — usually involving K, T[K], or both.
This is how Partial, Required, Readonly, and many utility types are built. Looking at one:
type Partial<T> = { [K in keyof T]?: T[K] };
Loop over T's keys, mark each optional with ?, keep the original value type. Three changes from the identity mapped type, none of them complicated.
Modifiers: + and -
Mapped types can add or remove modifiers explicitly. +? adds optional, -? removes optional. +readonly adds readonly, -readonly removes it. Required<T> uses -? to strip optionality.
The plus signs are usually omitted (they're the default direction). The minus signs are what you write when you want to remove a modifier the keys already have.
Key remapping with as
TypeScript 4.1 added as to mapped types: { [K in keyof T as NewKey]: ... }. The NewKey can be a string-manipulating type expression (often a template literal) that transforms the key on its way through. This lets you build types like 'add a get prefix to every key.'