Псевдонимы типов
У настоящей анкеты есть название, напечатанное сверху: «Анкета сотрудника». Никто не перечисляет вслух все её поля. Говорят «заполните анкету сотрудника», и всем понятно, о каком бланке речь.
Пока у формы объекта нет названия, запись { name: string; age: number } приходится повторять везде, где нужен пользователь: три функции — три одинаковые записи. А если в анкету добавят поле email, править придётся все три, и одну из них можно пропустить.
Ключевое слово type даёт форме имя:
type User = {
name: string;
age: number;
};
function describe(user: User): string {
return `${user.name}, ${user.age}`;
}
function olderOf(a: User, b: User): User {
return a.age >= b.age ? a : b;
}
const ann: User = { name: "Ann", age: 30 };
console.log(describe(olderOf(ann, { name: "Bob", age: 25 }))); // Ann, 30Давайте разберём пример:
- Строки 1–4 объявляют псевдоним типа
User— имя для формы{ name: string; age: number }. Такую запись вы уже видели у списка литералов,type Size = "S" | "M" | "L"; здесь имя получает форма объекта. describeпринимаетUserи возвращает строку.olderOfпринимает двух пользователей и возвращает старшего — тожеUser.- Константа
annобъявлена с типомUser, и компилятор проверяет её литерал так же, как проверял бы полную запись формы. - Программа печатает
Ann, 30: из двух пользователей старшеann.
Как устроено объявление type
Объявление type User = { … }; состоит из четырёх частей:
- ключевое слово
type; - имя, по соглашению с большой буквы:
User,Order,Point; - знак
=и сам тип; - точка с запятой в конце.
Псевдоним можно указать везде, где пишут тип: у переменной, у параметра, у результата функции, внутри другого типа. Как и всё, что относится к типам, он существует только для компилятора и в JavaScript-файл не попадает.
Псевдоним для объединения
type даёт имя любому типу: форме объекта, как User, списку литералов, как Size, и объединению обычных типов:
type Id = string | number;
function showId(id: Id) {
console.log(`id: ${id}`);
}
showId(7); // id: 7
showId("a-15"); // id: a-15Имя Id короче, чем string | number, и говорит, зачем это значение нужно. Если позже идентификаторы станут только строками, достаточно поправить одну строку с type.
Ошибки называют имя
Когда у типа есть имя, компилятор пишет в сообщениях его, а не всю форму:
type User = { name: string; age: number };
const bob: User = { name: "Bob" }; // ✗error TS2741: Property 'age' is missing in type '{ name: string; }' but required in type 'User'.Без псевдонима в конце этого сообщения стояла бы вся форма { name: string; age: number; }, а здесь — короткое User. Редактор тоже показывает имя: подсказка над bob скажет User. С объединением так же: передайте в showId значение true, и ошибка закончится словами parameter of type 'Id'.
Имя, а не новый тип
Псевдоним не создаёт нового типа, а даёт второе имя существующему. Здесь аналогия с анкетой перестаёт работать: в отделе кадров две анкеты с разными названиями — два разных бланка, даже если поля у них одинаковые. Для TypeScript запись type Age = number значит только «Age — другое имя для number»:
- в
Ageможно положить любое число; - значение типа
Ageподходит везде, где ждутnumber; - у константы
const a: Age = 30редактор покажет типnumber, а неAge.
Частая ошибка
Ждать, что компилятор различит два псевдонима одного типа:
type UserId = number;
type OrderId = number;
function findUser(id: UserId) {
console.log(`user #${id}`);
}
const orderId: OrderId = 42;
findUser(orderId); // ✗Компилятор промолчит, и программа напечатает user #42: функция станет искать пользователя по номеру заказа. UserId и OrderId — оба number, а разницы между именами одного типа компилятор не видит. Псевдоним помогает читателю кода, но от путаницы не защищает, поэтому такие места проверяйте сами — например, давайте параметрам и переменным говорящие имена.
Главное
type Имя = тип;даёт имя любому типу: форме объекта, объединению, набору литералов.- Псевдоним объявляют один раз и пишут везде, где нужен тип, а форму меняют в одном месте.
- В ошибках и подсказках редактора стоит имя псевдонима объекта или объединения, а не вся форма.
- Псевдоним — второе имя, а не новый тип:
UserIdиOrderIdдля компилятора одинаковы.