A mapped type iterates a union of keys and builds one property per member: { [K in "a" | "b"]: number }. The key union is usually keyof T, and T[K] reads the original property type.
Modifiers. When the keys come from keyof T (or from a type parameter constrained to keyof T), the mapped type is homomorphic: it copies each property's readonly and ? from T. You change that with + / - prefixes (PR 21919):
-readonlyremoves readonly,+readonly(or plainreadonly) adds it.-?makes a property required and, understrictNullChecks, also stripsundefinedthat?had added;?/+?makes it optional.
This is how Partial, Required and Readonly are defined.
Key remapping (TS 4.1): [K in keyof T as NewKey]: T[K]. NewKey can be any type computed from K, typically a template literal (get${Capitalize<K>}). If it resolves to never for a key, that property is dropped, so as Exclude<K, "kind"> filters without a helper Omit. Because as is a clause on a keyof T mapping, modifiers are still copied. K in the as clause ranges over the original keys, so T[K] stays valid.
Behaviours to know:
- Homomorphic mapped types distribute over unions and leave primitives unchanged; applied to arrays and tuples they map the elements and keep the array or tuple shape.
- You cannot declare extra properties next to the
[K in ...]part (TS7061); intersect two types instead. - Iterating
Exclude<keyof T, X>directly (noas) is not homomorphic and loses modifiers. - With
as, the key set can be any union, not onlystring | number | symbol: you can map over a union of objects withas E["kind"].