Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що таке "mapped type"?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Mapped type** - це **тип, що створюється на основі іншого типу (або множини ключів)** шляхом **ітерації по його ключах** і **модифікації** властивостей (їхніх типів, імен, модифікаторів). **Ключове:** це можна назвати "типовим аналогом циклу `for...in` по ключах об'єкта".Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## Що таке Mapped Type **Mapped type** - це **тип, що створюється на основі іншого типу (або множини ключів)** шляхом **ітерації по його ключах** і **модифікації** властивостей (їхніх типів, імен, модифікаторів). Можна сказати, що це "типовий аналог циклу `for...in` по ключах об'єкта". --- ### Синтаксис ```javascript type NewType = { [K in Keys]: Type; } ``` - `K` - змінна, що представляє ключ; - `in` - оператор, який перебирає значення об'єднання `Keys`; - `Type` - тип значення, який ми призначаємо кожному ключу. --- ## Приклад 1. Простий mapping ```javascript type User = { name: string; age: number; }; type Nullable<T> = { [K in keyof T]: T[K] | null; }; // Перетворений тип: type NullableUser = Nullable<User>; /* { name: string | null; age: number | null; } */ ``` Тут: - `keyof T` - це `"name" | "age"`; - `[K in keyof T]` - перебирає `"name"` і `"age"`; - кожному полю присвоюється `T[K] | null`. --- ## Приклад 2. Використання модифікаторів У mapped types можна **змінювати модифікатори** властивостей: | Модифікатор | Що робить | |---|---| | `?` | робить властивість **опціональною** | | `-?` | робить властивість **обов'язковою** | | `readonly` | робить властивість **тільки для читання** | | `-readonly` | прибирає `readonly` | --- ### Приклад ```javascript type Optional<T> = { [K in keyof T]?: T[K]; }; type ReadonlyCopy<T> = { readonly [K in keyof T]: T[K]; }; type Mutable<T> = { -readonly [K in keyof T]: T[K]; }; type RequiredCopy<T> = { [K in keyof T]-?: T[K]; }; ``` --- ## Приклад 3. Реалізація стандартних утиліт Ось як влаштовані багато вбудованих utility types: ```javascript // Partial<T> type Partial<T> = { [K in keyof T]?: T[K]; }; // Required<T> type Required<T> = { [K in keyof T]-?: T[K]; }; // Readonly<T> type Readonly<T> = { readonly [K in keyof T]: T[K]; }; // Pick<T, K> type Pick<T, K extends keyof T> = { [P in K]: T[P]; }; // Record<K, T> type Record<K extends string | number | symbol, T> = { [P in K]: T; }; ``` --- ## Приклад 4. Перетворення ключів Можна **змінювати імена властивостей** за допомогою конструкції `as` (TypeScript >= 4.1): ```javascript type UppercaseKeys<T> = { [K in keyof T as Uppercase<string & K>]: T[K]; }; type User = { name: string; age: number; }; type UpperUser = UppercaseKeys<User>; /* { NAME: string; AGE: number; } */ ``` > Тут `as Uppercase<...>` перейменовує ключі у верхній регістр. --- ## Приклад 5. Фільтрація ключів Можна навіть **видаляти** ключі з типу за допомогою `never`: ```javascript type RemoveNever<T> = { [K in keyof T as T[K] extends never ? never : K]: T[K]; }; type Example = { a: string; b: never; c: number; }; type Clean = RemoveNever<Example>; // { a: string; c: number } ``` --- ## Приклад 6. Комбінування з conditional types Mapped types часто **поєднуються** з conditional types для гнучких перетворень: ```javascript type MakeOptionalIfNullable<T> = { [K in keyof T as null extends T[K] ? K : never]?: T[K]; }; type User = { id: number; name: string | null; age: number; }; type OptionalNullable = MakeOptionalIfNullable<User>; // { name?: string | null } ``` --- ## Приклад 7. Динамічне створення API типів ```javascript type Events = "click" | "submit" | "hover"; type EventHandlers = { [E in Events as `on${Capitalize<E>}`]: (event: E) => void; }; /* { onClick: (event: "click") => void; onSubmit: (event: "submit") => void; onHover: (event: "hover") => void; } */ ``` --- ## Як думає TypeScript TypeScript ніби робить таке: ```javascript // псевдокод let result = {}; for (let key of Keys) { result[key] = Type; } return result; ``` --- ## Переваги mapped types Дозволяють **автоматично створювати похідні типи** Виключають дублювання коду (не потрібно вручну переписувати поля) Чудово працюють з `keyof`, `Conditional Types`, `Template Literals` Основа всіх вбудованих утилітарних типів --- ## Підсумок | Поняття | Опис | |---|---| | **Mapped type** | Тип, що створюється шляхом ітерації по ключах іншого типу | | **Синтаксис** | `[K in Keys]: Type` | | **Додаткові можливості** | `readonly`, `?`, `as`, `never` | | **Заснований на** | `keyof`, `in`, `conditional types` | | **Приклади в TS** | `Partial`, `Required`, `Readonly`, `Pick`, `Record` |Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.