Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое Mapped Types (Сопоставленные Типы) в TypeScript?
Mapped Types — это мощный механизм в TypeScript, позволяющий создавать новые типы на основе существующих, путем итерации по ключам (свойствам) исходного типа и их трансформации. По сути, это инструмент для программирования на уровне системы типов, который помогает избежать дублирования кода в определениях типов, обеспечивая при этом гибкость и безопасность.
Основной принцип работы
Mapped Types используют синтаксис, напоминающий цикл for...in в JavaScript, но применяемый к ключам типа. Базовая структура выглядит так:
type MappedType<T> = {
[P in keyof T]: T[P];
};
Здесь:
keyof T— создает объединение (union) всех ключей (имен свойств) типаT.P in— итерация по каждому ключу в этом объединении.T[P]— получение типа значения свойстваPиз исходного типаT. Это индексируемый доступ (indexed access type).- Результат — новый объектный тип с теми же ключами и типами значений, что и у
T. На данном примере это точная копияT.
Ключевые возможности и модификаторы
Сила Mapped Types раскрывается при использовании модификаторов readonly и ? (опциональность), а также операторов + и - для их явного добавления или удаления.
// Сделать все свойства только для чтения
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
// Сделать все свойства опциональными
type Partial<T> = {
[P in keyof T]?: T[P];
};
// Удалить опциональность (сделать обязательными)
type Required<T> = {
[P in keyof T]-?: T[P];
};
// Удалить модификатор readonly
type Mutable<T> = {
-readonly [P in keyof T]: T[P];
};
Практические примеры использования
-
Глубокая трансформация (Deep Mapped Types): Часто требуется применить преобразование рекурсивно ко всем вложенным объектам.
type DeepPartial<T> = { [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P]; }; interface User { id: number; profile: { name: string; age: number; }; } const partialUser: DeepPartial<User> = { profile: { name: "Alex" } // age и id можно не указывать }; -
Фильтрация ключей: Используя условные типы (
extends), можно создавать типы на основе подмножества свойств.// Тип только для строковых свойств type StringProperties<T> = { [P in keyof T as T[P] extends string ? P : never]: T[P]; }; // Тип, который убирает из модели методы, оставляя только данные type DataOnly<T> = { [P in keyof T as T[P] extends Function ? never : P]: T[P]; }; -
Изменение имен ключей (Key Remapping): С помощью конструкции
asв TypeScript 4.1+ можно создавать новые имена свойств.// Добавить префикс "get" к каждому ключу type Getters<T> = { [P in keyof T as `get${Capitalize<string & P>}`]: () => T[P]; }; interface Person { name: string; age: number; } // Получится тип: { getName: () => string; getAge: () => number; } -
Создание гомоморфных и негомоморфных типов: Гомоморфные типы (как
Readonly<T>) сохраняют модификаторы (readonly,?) исходного типа. Негомоморфные — нет. Например,Record<K, V>не является гомоморфным — он создает новый тип "с нуля".
Встроенные Mapped Types в TypeScript
TypeScript включает несколько встроенных утилитарных типов, реализованных через Mapped Types:
Readonly<T>,Partial<T>,Required<T>— как показано выше.Pick<T, K>— создает тип, выбирая только указанные ключиKизT.Record<K, T>— создает тип с ключами типаKи значениями типаT. По сути, это словарь или карта.
// Пример Pick и Record
interface Product {
id: number;
name: string;
price: number;
description: string;
}
type ProductPreview = Pick<Product, 'id' | 'name'>; // { id: number; name: string; }
type PageHeaders = Record<'home' | 'about', string>; // { home: string; about: string; }
Значение для разработчика
Использование Mapped Types кардинально повышает уровень абстракции при работе с типами. Вместо ручного описания похожих интерфейсов (User, UserPartial, UserReadonly) вы создаете одну основную модель и генерируете производные типы. Это:
- Снижает количество ошибок и опечаток.
- Упрощает рефакторинг — изменение основного типа автоматически обновит все производные.
- Повышает читаемость и выразительность кода, явно указывая на намерения (например, "это частичная версия модели для обновления").
- Открывает возможности для создания сложных, но типобезопасных абстракций, таких как валидаторы, сериализаторы или конфигурации для API-клиентов.
Таким образом, Mapped Types — это не просто синтаксический сахар, а фундаментальный инструмент для построения масштабируемых, легко поддерживаемых и строго типизированных приложений на TypeScript, позволяющий применять принципы DRY (Don't Repeat Yourself) на уровне системы типов.