Хотите заказать веб-сайт? Связаться с нами

Обзор компилятора TypeScript и вывод типов

В прошлом уроке мы разобрались, чем tsx отличается от tsc, и научились запускать и компилировать файлы. Но что именно происходит внутри компилятора, когда он превращает TypeScript в JavaScript? Сегодня заглянем под капот, посмотрим, как работает вывод типов, и коротко обозначим темы, которые нас ждут дальше: интерфейсы, дженерики и tsconfig.json.

Обзор компилятора TypeScript и вывод типов

Подготовка

Создайте файл infer.ts со следующим содержимым:

function double(x: number) {
  return x * 2;
}
 
let message = "Hello, TypeScript!";
const numbers = [1, 2, 3];
 
console.log(double(21));

Обратите внимание: у функции double есть тип только у параметра, а у переменных message и numbers аннотаций типов нет вообще. Сейчас разберёмся, почему это не проблема.

Что происходит при компиляции

Когда вы запускаете tsc, компилятор проходит через несколько этапов:

Этап Что происходит
Парсинг TypeScript читает файл и строит дерево синтаксиса
Проверка типов Компилятор ищет несоответствия типов и выводит ошибки
Стирание типов Аннотации и интерфейсы удаляются — в JavaScript их не существует
Понижение синтаксиса Современный синтаксис адаптируется под указанный target
Эмит Создаётся готовый .js-файл, если не указан --noEmit

Скомпилируйте наш файл:

npx tsc infer.ts

Откройте получившийся infer.js:

function double(x) {
    return x * 2;
}
let message = "Hello, TypeScript!";
const numbers = [1, 2, 3];
console.log(double(21));

Все аннотации типов исчезли — остался чистый JavaScript. Именно поэтому TypeScript называют надмножеством JavaScript: типы существуют только на этапе разработки и проверки, а в браузере или Node.js их уже нет.

Вывод типов на практике

Шаг 1: Смотрим на вывод без аннотаций

Наведите курсор на переменную message в редакторе — VS Code покажет тип string, хотя мы его не писали явно. То же самое произойдёт с numbers — там будет тип number[]. TypeScript вывел эти типы самостоятельно, взглянув на присвоенные значения.

Шаг 2: Проверяем, что вывод типов действительно защищает код

Допишите в конец файла ошибочную строку:

message = 42;

Запустите проверку:

npx tsc infer.ts --noEmit

Компилятор откажется это пропустить:

infer.ts:8:1 - error TS2322: Type 'number' is not assignable to type 'string'.
 
8 message = 42;
  ~~~~~~~
 
Found 1 error in infer.ts:8

Хотя мы нигде не написали : string, TypeScript всё равно знает, что message — строка, и не даёт присвоить туда число.

Если вы не уверены, какой тип вывел TypeScript, наведите курсор на переменную в VS Code — во всплывающей подсказке всегда виден итоговый выведенный тип. Это быстрее, чем запускать компилятор каждый раз, когда нужно что-то проверить.

Что нас ждет дальше

Вывод типов отлично работает для простых случаев, но для более сложных структур данных и функций нужны дополнительные инструменты. В ближайших уроках мы разберём:

  1. Интерфейсы — способ описывать форму объектов, чтобы не повторять одну и ту же структуру вручную.
  2. Дженерики — типы, которые принимают другой тип как параметр, делая функции и структуры переиспользуемыми.
  3. tsconfig.json — файл конфигурации, который управляет поведением компилятора для всего проекта, а не только для одного файла.

Пока просто взгляните, как это будет выглядеть — подробно разберём каждую тему отдельно:

interface User {
  name: string;
  age: number;
}
 
function identity<T>(value: T): T {
  return value;
}
{
  "compilerOptions": {
    "target": "ES2020",
    "strict": true
  }
}

Запуск и проверка

Убедитесь, что вы прошли весь путь от исходника до ошибки компиляции:

npx tsc infer.ts
npx tsc infer.ts --noEmit

Первая команда создаст infer.js без ошибочной строки message = 42;, вторая — покажет ошибку типов, если вы её добавили, и ничего не создаст.

Бонус: полезные флаги компилятора

  1. Флаг --target задаёт версию JavaScript на выходе, например --target es2017.
  2. Флаг --outDir указывает папку, куда складывать скомпилированные файлы, например --outDir dist.
  3. Флаг --declaration создаёт рядом с .js-файлом файл описания типов .d.ts — он пригодится, если ваш код будут использовать другие TypeScript-проекты.

Не запоминайте флаги компилятора наизусть — гораздо удобнее вынести их один раз в tsconfig.json, а потом просто запускать tsc без аргументов. Мы разберём это подробно через несколько уроков.

Итог

Сегодня мы заглянули внутрь процесса компиляции TypeScript:

  1. Компилятор проходит через парсинг, проверку типов, стирание типов и эмит готового JavaScript.
  2. Вывод типов позволяет TypeScript определять типы автоматически, даже без явных аннотаций.
  3. Компилятор всё равно ловит ошибки, даже если тип нигде не был указан вручную.
  4. Впереди — интерфейсы, дженерики и настройка компилятора через tsconfig.json.

В следующем уроке разберём входные и выходные файлы tsc подробнее — какие флаги отвечают за то, что компилятор читает и что создаёт на выходе.

Теги: