Вспомогательные типы в TypeScript
В TypeScript встроен набор вспомогательных типов, которые изменяют или переиспользуют другие типы. Их называют вспомогательными типами (utility types).
В этой главе рассмотрены самые популярные из них.
Partial
Partial берёт тип объекта и делает все его свойства необязательными.
Пример
Partial<Point> позволяет начать с пустого объекта и задать x и y позже.
Partial делает каждое свойство типа объекта необязательным.
Объявите интерфейс Point с x: number и y: number, создайте pointPart с типом Partial<Point>, начав с пустого объектного литерала, затем присвойте pointPart.x = 10. Файл только объявляет и присваивает; он ничего не печатает.
Вывод: программа на TypeScript и захваченный вывод
interface Point {
x: number;
y: number;
}
let pointPart: Partial<Point> = {}; // `Partial` делает x и y необязательными
pointPart.x = 10;
Required
Required берёт тип объекта и делает все его свойства обязательными, даже те, что помечены как необязательные с помощью ?.
Пример
Свойство mileage в Car необязательное, но Required<Car> требует задать ему значение.
Required превращает необязательные свойства в обязательные.
Объявите интерфейс Car с make: string, model: string и необязательным mileage?: number, затем создайте myCar с типом Required<Car>, где make равно 'Ford', model — 'Focus', а mileage — 12000, добавив комментарий о том, что Required требует обязательно задать mileage. Ничего не печатается.
Вывод: программа на TypeScript и захваченный вывод
interface Car {
make: string;
model: string;
mileage?: number;
}
let myCar: Required<Car> = {
make: 'Ford',
model: 'Focus',
mileage: 12000 // `Required` требует, чтобы mileage был задан
};
Record
Record — это краткий способ описать тип объекта с одним типом ключа и одним типом значения.
Примечание: Record<string, number> означает то же самое, что и { [key: string]: number }.
Пример
Каждый ключ в nameAgeMap должен быть строкой, а каждое значение — числом.
Record, используемый для описания отображения строковых ключей в числовые значения.
Создайте константу nameAgeMap с типом Record<string, number>, содержащую 'Alice' со значением 21 и 'Bob' со значением 25. Ничего не печатается.
Вывод: программа на TypeScript и захваченный вывод
const nameAgeMap: Record<string, number> = {
'Alice': 21,
'Bob': 25
};
Omit
Omit удаляет из типа объекта те ключи, которые вы перечислили.
Пример
Omit<Person, 'age' | 'location'> оставляет только name, поэтому age и location нельзя задать у bob.
Omit удаляет из типа объекта перечисленные ключи.
Объявите интерфейс Person с name: string, age: number и необязательным location?: string, затем создайте bob с типом Omit<Person, 'age' | 'location'>, содержащий только name со значением 'Bob', с комментарием, объясняющим, что age и location были удалены и их нельзя здесь определить. Ничего не печатается.
Вывод: программа на TypeScript и захваченный вывод
interface Person {
name: string;
age: number;
location?: string;
}
const bob: Omit<Person, 'age' | 'location'> = {
name: 'Bob'
// `Omit` удалил age и location из типа, и здесь их нельзя определить
};
Pick
Pick оставляет только перечисленные вами ключи и убирает из типа объекта всё остальное.
Пример
Pick<Person, 'name'> оставляет только name, поэтому age и location исчезают из типа.
Pick оставляет только перечисленные ключи типа объекта.
Объявите интерфейс Person с name: string, age: number и необязательным location?: string, затем создайте bob с типом Pick<Person, 'name'>, содержащий только name со значением 'Bob', с комментарием, объясняющим, что оставлено только name, поэтому age и location нельзя здесь определить. Ничего не печатается.
Вывод: программа на TypeScript и захваченный вывод
interface Person {
name: string;
age: number;
location?: string;
}
const bob: Pick<Person, 'name'> = {
name: 'Bob'
// `Pick` оставил только name, поэтому age и location удалены из типа и здесь их нельзя определить
};
Exclude
Exclude удаляет члены из типа-объединения.
Пример
После Exclude<Primitive, string> значение может быть числом или логическим значением, но не строкой.
Exclude удаляет член из типа-объединения.
Объявите псевдоним типа Primitive как string | number | boolean, затем создайте константу value с типом Exclude<Primitive, string> и значением true, с комментарием о том, что строку здесь использовать нельзя, потому что Exclude её удалил. Ничего не печатается.
Вывод: программа на TypeScript и захваченный вывод
type Primitive = string | number | boolean
const value: Exclude<Primitive, string> = true; // строку здесь использовать нельзя, так как `Exclude` удалил её из типа.
ReturnType
ReturnType берёт тип функции и даёт вам тип того, что эта функция возвращает.
Пример
ReturnType<PointGenerator> — это тип объекта { x: number; y: number; }.
ReturnType извлекает тип возвращаемого значения из типа функции.
Объявите псевдоним типа PointGenerator для функции без параметров, возвращающей { x: number; y: number; }, затем создайте константу point с типом ReturnType<PointGenerator>, где x равно 10, а y — 20. Ничего не печатается.
Вывод: программа на TypeScript и захваченный вывод
type PointGenerator = () => { x: number; y: number; };
const point: ReturnType<PointGenerator> = {
x: 10,
y: 20
};
Parameters
Parameters берёт тип функции и даёт вам типы её параметров в виде кортежа (типа массива). По индексу можно получить тип одного параметра.
Пример
Parameters<PointPrinter>[0] — это тип первого параметра: { x: number; y: number; }.
Parameters извлекает типы параметров типа функции в виде кортежа.
Объявите псевдоним типа PointPrinter для функции, принимающей p: { x: number; y: number; } и возвращающей void, затем создайте константу point с типом Parameters<PointPrinter>[0], где x равно 10, а y — 20. Ничего не печатается.
Вывод: программа на TypeScript и захваченный вывод
type PointPrinter = (p: { x: number; y: number; }) => void;
const point: Parameters<PointPrinter>[0] = {
x: 10,
y: 20
};
Readonly
Readonly создаёт новый тип, в котором каждое свойство доступно только для чтения. Как только свойство получило значение, изменить его нельзя.
Примечание: TypeScript запрещает изменение только на этапе компиляции. В скомпилированном JavaScript такой защиты нет, поэтому во время выполнения свойство readonly всё ещё можно перезаписать.
Пример
Присваивание нового значения name для Readonly<Person> — это ошибка компиляции.
Readonly запрещает присваивание свойствам после создания объекта.
Объявите интерфейс Person с name: string и age: number, создайте константу person с типом Readonly<Person>, где name равно "Dylan", а age — 35, затем попробуйте присвоить person.name значение 'Israel'. Оставьте эту строку, чтобы компилятор сообщил об ошибке TS2540 (нельзя присвоить значение свойству, доступному только для чтения).
Вывод: программа на TypeScript и захваченный вывод
interface Person {
name: string;
age: number;
}
const person: Readonly<Person> = {
name: "Dylan",
age: 35,
};
person.name = 'Israel'; // prog.ts(11,8): error TS2540: Cannot assign to 'name' because it is a read-only property.