Перейти к содержимому
Теория · Аннотации и вывод типов · урок 1 из 9

Аннотации типов

Чему вы научитесь

Чему вы научитесь:

  • указывать тип у переменной, у параметра и у результата функции;
  • понимать, где TypeScript выводит тип сам, а где его нужно написать;
  • объяснять, почему let a = 5 получает тип number, а const b = 5 — литеральный тип 5;
  • отличать запрет на новое значение у const от неизменяемого объекта.
Открытая банка с этикеткой number ждёт новые плитки, а запечатанная банка с этикеткой 5 держит одну плитку

Представьте кухонную полку с банками. На каждой банке наклейка: «Соль», «Сахар», «Гречка». Наклейка говорит, что можно насыпать в банку, ещё до того, как её откроют. Если кто-то начнёт сыпать сахар в банку с надписью «Соль», ошибку заметят сразу, а не тогда, когда суп окажется сладким.

У переменных JavaScript таких наклеек нет. Сегодня в price лежит число, а завтра туда запишут строку "бесплатно", и программа сломается совсем в другом месте — там, где у price вызовут toFixed(2). Чтобы найти причину, придётся идти назад по коду и искать, кто и когда положил туда строку.

В TypeScript наклейку можно написать самому. Аннотация типа — это запись : тип после имени, которая говорит компилятору, значения какого типа здесь допустимы. Двоеточие читают как «имеет тип»: count: number — «count имеет тип number».

Три места для аннотации

Аннотацию пишут в трёх местах: у переменной, у параметра функции и у результата функции. В этом примере есть все три:

TypeScript
let count: number = 0;

function withDelivery(price: number): number {
    return price + 300;
}

count = count + 1;
console.log(count, withDelivery(1200)); // 1 1500

Программа компилируется без ошибок и печатает 1 1500. Разберём каждое место по отдельности.

Переменная

Строка let count: number = 0; состоит из трёх частей:

  • let count — обычное объявление, как в JavaScript;
  • : number — аннотация: в count можно записывать только числа;
  • = 0 — начальное значение, и оно тоже должно быть числом.

Дальше компилятор сверяет с наклейкой каждое присваивание. count = count + 1 кладёт число в числовую переменную, и проверка проходит. А строка count = "два" дала бы ошибку TS2322, которую вы уже встречали в первой теме.

Параметр функции

Запись price: number в скобках — наклейка на вход функции. Телу функции она обещает, что в price придёт число, а от того, кто вызывает функцию, требует передать именно число:

TypeScript
function withDelivery(price: number): number {
    return price + 300;
}

withDelivery("1200"); // ✗
TEXT
error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.

Сообщение значит: «аргумент типа string нельзя передать в параметр типа number». tsc показывает ошибку в строке вызова, хотя функция объявлена выше. Если бы JavaScript выполнил этот вызов, "1200" + 300 склеил бы строки, и вместо 1500 получилось бы "1200300".

Результат функции

Аннотация после скобок с параметрами — ): number — это наклейка на выход. Функция обещает вернуть число, и компилятор проверяет каждый return в её теле:

TypeScript
function withDelivery(price: number): number {
    return "Итого: " + (price + 300); // ✗
}
TEXT
error TS2322: Type 'string' is not assignable to type 'number'.

Ошибка стоит на строке с return: из функции, которая обещала число, нельзя вернуть строку. Искать причину среди вызовов withDelivery не придётся — ошибку видно там, где нарушено обещание.

Кто читает наклейки

Здесь аналогия с банками заканчивается. Наклейку на банке можно не заметить, а аннотацию tsc проверяет каждый раз, когда компилирует файл. Но в JavaScript, который он пишет, аннотаций уже нет: при запуске программы типы никто не проверяет.

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

Аннотацию принимают за преобразование и ждут, что строка станет числом:

TypeScript
let quantity: number = "5"; // ✗
TEXT
error TS2322: Type 'string' is not assignable to type 'number'.

Аннотация ничего не превращает, она только проверяет. Строку, например из поля формы, сначала переводят в число — Number("5"), — и уже результат кладут в переменную типа number.

Главное

  • Аннотация типа — запись : тип после имени; двоеточие читают как «имеет тип».
  • Аннотацию пишут у переменной (let count: number), у параметра (price: number) и у результата функции (): number).
  • tsc сверяет с аннотацией каждое присваивание, каждый вызов и каждый return.
  • Аннотация ничего не преобразует: строку "5" нельзя записать в переменную типа number.