Mapped type проходить по ключах і будує новий тип: { [K in keyof T]: ... }. Крім типу значень, можна змінювати модифікатори й самі ключі.
Модифікатори readonly і ? - додати (+, можна опускати) чи прибрати (-):
type Mutable<T> = { -readonly [K in keyof T]: T[K] };
type Concrete<T> = { [K in keyof T]-?: T[K] }; // усі поля обов'язкові
type Locked = { readonly id: number; name?: string };
type M = Mutable<Locked>; // { id: number; name?: string }
type C = Concrete<Locked>; // { readonly id: number; name: string }
Вбудовані Partial, Required, Readonly - саме такі типи.
Перейменування ключів через as (TS 4.1+):
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
type UserGetters = Getters<{ name: string; age: number }>;
// { getName: () => string; getAge: () => number }
string & K - бо ключі можуть бути number | symbol, а Capitalize працює лише з рядками.
Фільтрація ключів - якщо as дає never, ключ зникає:
type OnlyStrings<T> = {
[K in keyof T as T[K] extends string ? K : never]: T[K];
};
type S = OnlyStrings<{ id: number; name: string; email: string }>;
// { name: string; email: string }
type WithoutMeta<T> = { [K in keyof T as Exclude<K, `_${string}`>]: T[K] };
Практичні застосування:
- обробники подій з полів:
{ [K in keyof State as \on${Capitalize<...>}Change`]: (value: State[K]) => void }`; - типи форм: з моделі даних - тип помилок
{ [K in keyof T]?: string[] }(як помилки валідації Laravel); - вибір полів за типом значень: лише числові поля для сортування, лише булеві для фільтрів.
Важлива деталь: mapped type вигляду { [K in keyof T]: ... } (гомоморфний) зберігає модифікатори вихідного типу - readonly і ? переходять автоматично. Якщо перебирати не keyof T, а довільне об'єднання ([K in 'a' | 'b']), модифікатори не копіюються.
Масиви й кортежі у гомоморфних mapped types лишаються масивами й кортежами - тип застосовується до елементів, а не до методів масиву.
Докладніше в документації: Mapped types: перейменування ключів через as