Перейти к содержимому
Теория · Первые шаги · урок 6 из 7

Типы исчезают при компиляции

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

Посмотрим, что tsc оставит от файла hello.ts с аннотациями. Нажимайте «Следующий шаг» и следите, во что превращается каждая подсвеченная строка TypeScript.

ВживуюЧто tsc оставит от файлашаг 1 из 5

У параметра и у результата были аннотации : string — в JavaScript их нет, а функция осталась.

Подсветка показывает строку TypeScript и строку JavaScript, которая из неё получилась

Что осталось в hello.js

После компиляции в hello.js:

  • исчезли все аннотации: : string у параметра и результата, : string и : number у переменных;
  • осталось всё, что выполняется: функция, шаблонная строка, значения "Anna" и 3, вызов console.log;
  • в начале появилась строка "use strict"; — её дописал tsc. Это строгий режим самого JavaScript, а не tsc: к типам он отношения не имеет.

Получился обычный JavaScript, в котором нет ни слова о типах. Команда node hello.js выполнит его так же, как любой другой файл .js.

Зачем стирать типы

Почему бы не оставить аннотации в JavaScript? Потому что это не JavaScript. Встретив : string в файле .js, браузер или Node.js остановятся с синтаксической ошибкой ещё до первой строки. Поэтому tsc и вырезает типы: без них файл понятен и браузеру, и Node.js.

При запуске типов нет

Раз в hello.js типов нет, во время работы программы их никто не проверяет. Проверка была одна — до запуска, по тексту программы. Поэтому типы не защищают от данных, которые появляются только во время работы:

  • текста, который пользователь ввёл в форму;
  • ответа сервера;
  • содержимого файла.

В картинке с таможней такие данные попадают в страну в обход границы, без декларации: tsc их никогда не видел. Если значение нужно проверить, программа делает это сама, средствами JavaScript, например через typeof.

На собеседовании часто спрашивают, существуют ли типы TypeScript во время выполнения. Нет: tsc стирает их при компиляции, и в работающей программе остаётся только JavaScript.

Ошибка не мешает записать файл

Здесь картинка с таможней перестаёт работать. Настоящий таможенник задержит посылку с неверной декларацией, а tsc сообщает об ошибке и всё равно записывает .js. Проверка типов и запись JavaScript — две отдельные работы, и вторая не ждёт успеха первой.

Чтобы tsc не записывал файл, пока в коде есть ошибки, нужен флаг --noEmitOnError:

TEXT
$ tsc --noEmitOnError hello.ts

С ним при ошибке новый hello.js не появится. Старый, если он остался от прошлой компиляции, при этом не изменится.

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

Увидеть сообщение tsc, но всё равно запустить hello.js. Вернёмся к функции из первого урока темы:

TypeScript
function formatPrice(price: number): string {
    return price.toFixed(2);
}

console.log(formatPrice(100));
console.log(formatPrice("100")); // ✗
TEXT
error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.

tsc hello.ts сообщит об этой ошибке, но hello.js всё равно запишет. Команда node hello.js напечатает 100.00, а на втором вызове программа остановится:

TEXT
TypeError: price.toFixed is not a function

Типы стёрты, и строка "100" дошла до toFixed, как в JavaScript без всякого TypeScript. Исправление — сначала убрать ошибки, о которых сообщил tsc, и только потом запускать программу.

Главное

  • tsc сначала проверяет типы, а потом пишет JavaScript без них: это стирание типов.
  • В hello.js нет аннотаций, поэтому при запуске типы ничего не проверяют.
  • Данные, которые приходят во время работы, tsc не видел: их проверяют средствами JavaScript, например typeof.
  • tsc записывает .js даже при ошибках, а флаг --noEmitOnError это запрещает.