Преобразованные типы в TypeScript позволяют создавать новые типы путём трансформации свойств существующих типов.
- Преобразованные типы = трансформация каждого свойства типа.
- Общие типы:
Partial,Readonly,Pick,Omit,Record.
Пример
// Простой пример
type Person = { name: string; age: number };
type PartialPerson = { [P in keyof Person]?: Person[P] };
type ReadonlyPerson = { readonly [P in keyof Person]: Person[P] };
Базовый синтаксис преобразованных типов
Основной синтаксис
Преобразованные типы используют синтаксис { [P in K]: T }, где:
P— имя свойства, по которому идёт итерация;K— объединение имён свойств, по которым выполняется итерация;T— результирующий тип для каждого свойства.
Пример
// Определяем тип объекта
interface Person {
name: string;
age: number;
email: string;
}
// Создаём преобразованный тип, делающий все свойства опциональными
type PartialPerson = {
[P in keyof Person]?: Person[P];
};
// Использование
const partialPerson: PartialPerson = {
name: "John"
// age и email — опциональные свойства
};
// Создаём преобразованный тип, делающий все свойства доступными только для чтения
type ReadonlyPerson = {
readonly [P in keyof Person]: Person[P];
};
// Использование
const readonlyPerson: ReadonlyPerson = {
name: "Alice",
age: 30,
email: "alice@example.com"
};
// readonlyPerson.age = 31; // Ошибка: нельзя присвоить значение свойству 'age', так как оно доступно только для чтения
Встроенные преобразованные типы
Утилиты стандартной библиотеки
В TypeScript есть несколько полезных встроенных преобразованных типов:
Partial<T>— делает все свойства опциональными;Readonly<T>— делает все свойства доступными только для чтения;Pick<T, K>— выбирает подмножество ключей;Omit<T, K>— удаляет указанные ключи;Record<K, V>— сопоставляет ключи с типом значения.
Пример
interface User {
id: number;
name: string;
email: string;
isAdmin: boolean;
}
// Partial<T> — делает все свойства опциональными
type PartialUser = Partial<User>;
// Эквивалентно: { id?: number; name?: string; email?: string; isAdmin?: boolean; }
// Required<T> — делает все свойства обязательными
type RequiredUser = Required<Partial<User>>;
// Эквивалентно: { id: number; name: string; email: string; isAdmin: boolean; }
// Readonly<T> — делает все свойства доступными только для чтения
type ReadonlyUser = Readonly<User>;
// Эквивалентно: { readonly id: number; readonly name: string; ... }
// Pick<T, K> — создаёт тип с подмножеством свойств из T
type UserCredentials = Pick<User, "email" | "id">;
// Эквивалентно: { email: string; id: number; }
// Omit<T, K> — создаёт тип, удаляя указанные свойства из T
type PublicUser = Omit<User, "id" | "isAdmin">;
// Эквивалентно: { name: string; email: string; }
// Record<K, T> — создаёт тип с указанными ключами и типами значений
type UserRoles = Record<"admin" | "user" | "guest", string>;
// Эквивалентно: { admin: string; user: string; guest: string; }
Создание пользовательских преобразованных типов
Базовые пользовательские преобразователи
Вы можете создавать собственные преобразованные типы для трансформации типов определённым образом.
Пример
// Базовый интерфейс
interface Product {
id: number;
name: string;
price: number;
inStock: boolean;
}
// Создаём преобразованный тип для трансформации всех свойств в тип string
type StringifyProperties<T> = {
[P in keyof T]: string;
};
// Использование
type StringProduct = StringifyProperties<Product>;
// Эквивалентно: { id: string; name: string; price: string; inStock: string; }
// Создаём преобразованный тип, добавляющий функции валидации для каждого свойства
type Validator<T> = {
[P in keyof T]: (value: T[P]) => boolean;
};
// Использование
const productValidator: Validator<Product> = {
id: (id) => id > 0,
name: (name) => name.length > 0,
price: (price) => price >= 0,
inStock: (inStock) => typeof inStock === "boolean"
};
Изменение модификаторов свойств
Добавление и удаление модификаторов
Преобразованные типы также позволяют добавлять или удалять модификаторы свойств, такие как readonly и ? (опциональность).
Пример
// Базовый интерфейс с некоторыми readonly и опциональными свойствами
interface Configuration {
readonly apiKey: string;
readonly apiUrl: string;
timeout?: number;
retries?: number;
}
// Удаляем модификатор readonly у всех свойств
type Mutable<T> = {
-readonly [P in keyof T]: T[P];
};
// Использование
type MutableConfig = Mutable<Configuration>;
// Эквивалентно: { apiKey: string; apiUrl: string; timeout?: number; retries?: number; }
// Делаем все опциональные свойства обязательными
type RequiredProps<T> = {
[P in keyof T]-?: T[P];
};
// Использование
type RequiredConfig = RequiredProps<Configuration>;
// Эквивалентно: { readonly apiKey: string; readonly apiUrl: string; timeout: number; retries: number; }
Продвинутые преобразованные типы
Комбинирование с условными типами
Преобразованные типы становятся ещё мощнее при сочетании с условными типами.
Пример
// Базовый интерфейс
interface ApiResponse {
data: unknown;
status: number;
message: string;
timestamp: number;
}
// Условный преобразованный тип: преобразуем каждое числовое свойство в форматированную строку
type FormattedResponse<T> = {
[P in keyof T]: T[P] extends number ? string : T[P];
};
// Использование
type FormattedApiResponse = FormattedResponse<ApiResponse>;
// Эквивалентно: { data: unknown; status: string; message: string; timestamp: string; }
// Ещё пример: фильтруем только строковые свойства
type StringPropsOnly<T> = {
[P in keyof T as T[P] extends string ? P : never]: T[P];
};
// Использование
type ApiResponseStringProps = StringPropsOnly<ApiResponse>;
// Эквивалентно: { message: string; }
Ключевые выводы
Преобразованные типы позволяют единообразно трансформировать каждое свойство типа.
Ключевые концепции
- Трансформация типов: массовое изменение типов свойств;
- Модификаторы свойств: добавление или удаление модификаторов
readonlyи?; - Преобразование ключей: переименование или фильтрация свойств с помощью конструкций
as; - Композиция: сочетание с другими возможностями TypeScript.
Типичные сценарии применения
- Создание версий типов только для чтения;
- Трансформация всех свойств в опциональные или обязательные;
- Трансформация типов свойств (например, в nullable или readonly);
- Фильтрация свойств на основе их типов;
- Создание типобезопасных вспомогательных функций.