В TypeScript есть набор служебных типов, которые служат для удобного создания производных типов и обработки типичных задач, возникающих при работе с типами. Они упрощают рутинные операции с типами и позволяют экономить время и усилия при разработке.
Служебные типы являются частью стандарта TypeScript и находятся в глобальном пространстве имён, поэтому доступны без дополнительных импортов.
В этой главе мы рассмотрим наиболее популярные служебные типы.
Partial<Type>
Делает все свойства типа необязательными.
Это полезно, когда нужно создать объект, который частично заполняется пользователями или не обязан содержать все свойства исходного типа.
Пример
interface Person {
name: string;
age: number;
}
let partialPerson: Partial<Person> = { name: "John" };
// Теперь partialPerson может не содержать свойство 'age', так как оно стало необязательным.
Required<Type>
Делает все свойства типа обязательными.
Это полезно, когда нужно убедиться, что объект содержит все свойства, даже если изначально тип позволял пропуская некоторые из них.
Пример
interface Product {
name: string;
price?: number;
}
let product: Required<Product> = { name: "Phone", price: 500 };
// Теперь свойство 'price' стало обязательным.
Record<KeyType, ValueType>
Создаёт объект с заданными ключами и значениями.
Record позволяет быстро определить тип объекта с заданным типом ключа и значения.
Пример
const nameAgeMap: Record<string, number> = {
'Alice': 21,
'Bob': 25
};
// Эквивалентно { [key: string]: number }
Pick<Type, Keys>
Оставляет только указанные свойства типа.
Полезно, когда нужно выбрать подмножество свойств из типа, отбросив остальные.
Пример
interface Address {
country: string;
city: string;
zip: string;
}
let addressInfo: Pick<Address, "city" | "zip"> = { city: "Москва", zip: "123456" };
// Остальные свойства ("country") стали недоступны.
Omit<Type, Keys>
Удаляет указанные свойства из типа.
Противоположность Pick, когда нужно избавиться от определённых свойств.
Пример
interface Task {
id: number;
title: string;
completed: boolean;
}
let taskSummary: Omit<Task, "completed"> = { id: 1, title: "Finish report" };
// Свойство "completed" исключено из типа.
Exclude<Type, ExcludedUnion>
Удаляет из типа элементы, относящиеся к указанному объединению.
Это полезно, когда нужно избавиться от определённых элементов, содержащихся в типе.
Пример
type Pet = "dog" | "cat" | "fish";
let mammalPet: Exclude<Pet, "fish"> = "dog";
// Теперь mammalPet может быть только "dog" или "cat".
ReturnType<FuncType>
Извлекает тип возвращаемого значения из типа функции.
Это полезно, когда нужно извлечь тип возвращаемого значения функции и использовать его отдельно.
Пример
type FetchResponse = () => { success: boolean; data: any };
let response: ReturnType<FetchResponse> = { success: true, data: [] };
// Теперь response имеет тип { success: boolean; data: any }.
Parameters<FuncType>
Извлекает типы параметров функции как массив.
Это может пригодиться, когда нужно явно задекларировать типы параметров функции отдельно.
Пример
type DivideFunc = (a: number, b: number) => number;
let params: Parameters<DivideFunc> = [10, 2];
// Теперь params имеет тип [number, number].
Readonly<Type>
Создаёт новый тип, в котором все свойства становятся только для чтения, то есть их нельзя изменять после присвоения значения.
Учтите, что TypeScript предотвращает изменения на этапе компиляции, но теоретически, так как код компилируется в JavaScript, вы всё ещё можете переопределить свойство, помеченное как readonly.
Пример
interface Config {
port: number;
host: string;
}
let config: Readonly<Config> = { port: 8080, host: "localhost" };
// Попытка изменить config.host вызовет ошибку.
NonNullable<Type>
Удаляет из типа значения null и undefined.
Помогает избежать случаев, когда переменная может быть null или undefined, что улучшает безопасность кода.
Пример
type MaybeNumber = number | null | undefined;
let safeNum: NonNullable<MaybeNumber> = 10;
// Теперь safeNum не может быть null или undefined.
Extract<Type, Union>
Извлекает из типа только те элементы, которые относятся к указанному объединению.
Полезно, когда нужно выбрать определённые элементы из типа, основываясь на объединении.
Пример
type Event = "click" | "hover" | "resize";
let eventHandler: Extract<Event, "click" | "hover"> = "click";
// Теперь eventHandler может быть только "click" или "hover".
Как и зачем использовать служебные типы?
Служебные типы решают повседневные задачи типизации, позволяя разработчику:
- Сделать часть свойств объекта необязательной или доступной только для чтения.
- Создать подмножество свойств из объекта.
- Обеспечить строгую типизацию при работе с коллекциями и объектами.
- Легко формировать тип возвращаемого значения или параметров функции.
Их использование позволяет сильно сократить количество рутинной работы по типизации и делает код более надежным и стабильным.