Перейти к содержимому
Теория · Объектные типы · урок 2 из 7

Псевдонимы типов

У настоящей анкеты есть название, напечатанное сверху: «Анкета сотрудника». Никто не перечисляет вслух все её поля. Говорят «заполните анкету сотрудника», и всем понятно, о каком бланке речь.

Пока у формы объекта нет названия, запись { name: string; age: number } приходится повторять везде, где нужен пользователь: три функции — три одинаковые записи. А если в анкету добавят поле email, править придётся все три, и одну из них можно пропустить.

Ключевое слово type даёт форме имя:

TypeScript
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. Строки 1–4 объявляют псевдоним типа User — имя для формы { name: string; age: number }. Такую запись вы уже видели у списка литералов, type Size = "S" | "M" | "L"; здесь имя получает форма объекта.
  2. describe принимает User и возвращает строку.
  3. olderOf принимает двух пользователей и возвращает старшего — тоже User.
  4. Константа ann объявлена с типом User, и компилятор проверяет её литерал так же, как проверял бы полную запись формы.
  5. Программа печатает Ann, 30: из двух пользователей старше ann.

Как устроено объявление type

Объявление type User = { … }; состоит из четырёх частей:

  • ключевое слово type;
  • имя, по соглашению с большой буквы: User, Order, Point;
  • знак = и сам тип;
  • точка с запятой в конце.

Псевдоним можно указать везде, где пишут тип: у переменной, у параметра, у результата функции, внутри другого типа. Как и всё, что относится к типам, он существует только для компилятора и в JavaScript-файл не попадает.

Псевдоним для объединения

type даёт имя любому типу: форме объекта, как User, списку литералов, как Size, и объединению обычных типов:

TypeScript
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.

Ошибки называют имя

Когда у типа есть имя, компилятор пишет в сообщениях его, а не всю форму:

TypeScript
type User = { name: string; age: number };

const bob: User = { name: "Bob" }; // ✗
TEXT
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.

Частая ошибка

Ждать, что компилятор различит два псевдонима одного типа:

TypeScript
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 для компилятора одинаковы.