Mapped Types (Сопоставленные типы) — это мощный инструмент в TypeScript, позволяющий создавать новые типы на основе уже существующих, трансформируя их свойства. Это похоже на использование метода .map() для массивов, но применяется к типам.
Основной синтаксис выглядит так: { [P in K]: T }, где K — это набор ключей (обычно Union Type), по которым мы проходимся итерацией. Чаще всего используется оператор keyof для получения всех ключей существующего типа.
С помощью Mapped Types можно легко создавать утилиты, такие как Partial (делает все поля необязательными) или Readonly (запрещает изменение полей), не дублируя код вручную. Это основа принципа DRY (Don't Repeat Yourself) в типизации. В этом уроке мы разберем синтаксис итерации по ключам и базовые преобразования типов.
- Модуль 1: Введение в TypeScript
- Модуль 2: Примитивные типы
- Модуль 3: Специальные типы
- Модуль 4: Массивы
- Модуль 5: Кортежи (Tuples)
- Модуль 6: Объекты
- Модуль 7: Функции
- Модуль 8: Union типы
- Модуль 9: Литеральные типы
- Модуль 10: Type Aliases
- Модуль 11: Интерфейсы
- Модуль 12: Type Guards и Narrowing
- Модуль 13: Enums
- Модуль 14: Классы
- Модуль 15: Generics — основы
- Модуль 16: Generics — ограничения
- Модуль 17: Utility Types — базовые
- Модуль 18: Utility Types — работа с Union
- Модуль 19: Utility Types — функции
- Модуль 20: Type Assertions
- Модуль 21: Keyof и Typeof операторы
- Модуль 22: Mapped Types
- Основы Mapped Types.
- Модификаторы в Mapped Types (+, -).
- Key Remapping (as).
- Модуль 23: Conditional Types
- Модуль 24: Discriminated Unions
- Модуль 25: Модули и типы
- Модуль 26: Declaration Files
- Модуль 27: Типизация асинхронного кода
- Модуль 28: Практические паттерны
1. Синтаксис итерации
В этом задании вам предстоит вспомнить синтаксис Mapped Types в TypeScript. Ниже представлен фрагмент кода, в котором объявлен интерфейс и на его основе создаётся новый тип с помощью Mapped Type. Однако в определении Mapped Type пропущены ключевые слова, необходимые для итерации по ключам исходного интерфейса. Ваша задача — вставить пропущенные ключевые слова в правильные места, чтобы код был синтаксически корректным и создавал ожидаемый тип.
interface User {
id: number;
name: string;
email: string;
}
type ReadonlyUser = {
readonly [K input1S input2S User]: User[K];
};2. Добавление модификаторов
В этом задании вам предстоит заполнить пропуски в коде, реализующем пользовательский mapped type, аналогичный встроенному Readonly. Вам нужно выбрать правильный синтаксис для добавления модификатора 'readonly' перед ключом в квадратных скобках. Обратите внимание на расположение ключевого слова 'readonly' и использование оператора 'keyof'.
type MyReadonly<T> = {
input1S [K in keyof T]: T[K]
};
interface Book {
title: string;
author: string;
year: number;
}
type ReadonlyBook = MyReadonly<Book>;
// Теперь все свойства ReadonlyBook доступны только для чтения3. Предсказание типа свойства
Проанализируйте приведённый код TypeScript. Дан исходный интерфейс Person и Mapped Type BooleanPerson, который преобразует все свойства этого интерфейса. Внимательно изучите, как изменяются типы свойств, и выберите, каким будет тип конкретного свойства 'age' в результирующем типе BooleanPerson.
interface Person {
name: string;
age: number;
isStudent: boolean;
}
type BooleanPerson = {
[K in keyof Person]: boolean;
};
// Какого типа будет свойство 'age' в типе BooleanPerson?4. Исправление синтаксиса Mapped Type
В этом фрагменте кода TypeScript, демонстрирующем использование Mapped Types, допущена синтаксическая ошибка. В определении типа `ReadonlyProps` внутри конструкции `[K in keyof T]` пропущен или неправильно расставлен ключевой символ. Найдите строку с ошибкой и исправьте её, чтобы тип корректно создавал новый тип со всеми свойствами, доступными только для чтения.
type ReadonlyProps<T> = { [K in keyof T] T[K]}; interface User { name: string; age: number;} // После исправления тип ReadonlyProps<User> сделает все свойства доступными только для чтения5. Сборка утилиты Partial
Из предложенных строк соберите корректное определение типа MyPartial на TypeScript, который делает все свойства переданного типа опциональными (добавляет знак '?'). В решении должны использоваться только необходимые строки, лишние строки включать не нужно. Обратите внимание на синтаксис mapped types и правильную структуру объявления типа.
type MyPartial<T> = { [P in keyof T]?: T[P];};type Partial<T> = { [P in keyof T]: T[P];type Readonly<T> = {6. Определение итерируемого ключа
Внимательно изучите приведённый фрагмент кода TypeScript, содержащий определение Mapped Type. Ваша задача — найти и выделить кликом переменную типа, которая представляет собой 'текущий ключ' в итерации (тот самый ключ, который последовательно принимает значения из union-типа или набора ключей объекта). Не отмечайте другие части кода, такие как имена типов, ключевые слова или фигурные скобки.
type ComplexMappedType<T, U extends keyof T> = {
[{{P~|~t1}} in {{U~|~t2}}]: T[{{P~|~t3}}] extends string ? {{P~|~t4}} : never;
} & {
readonly [{{K~|~t5}} in keyof T as {{K~|~t6}} extends string ? {{K~|~t7}} : never]: boolean;
};7. Количество ключей
В данном фрагменте кода TypeScript определён интерфейс с тремя свойствами. Затем с помощью Mapped Type создаётся новый тип, который преобразует каждое свойство исходного интерфейса. Проанализируйте код и определите, сколько свойств будет у результирующего типа после применения Mapped Type. Введите одно число в поле ответа.
interface Person {
name: string;
age: number;
city: string;
}
type ReadonlyPerson = {
readonly [K in keyof Person]: Person[K];
};