- Главная
- Typescript
- Компилятор tsc: входные и выходные файлы
Компилятор tsc: входные и выходные файлы
В предыдущем уроке мы узнали, что происходит внутри компилятора в целом: парсинг, проверка типов, стирание аннотаций и эмит JavaScript. Сегодня сфокусируемся на двух конкретных вопросах: какие файлы tsc вообще готов читать, и что именно он создаёт на выходе — а заодно разберём флаги --noEmit, --checkJs и --strict, которые эти границы настраивают.
Подготовка
Создайте два файла. Первый — обычный TypeScript-файл app.ts:
function getLength(value) {
return value.length;
}
console.log(getLength("TypeScript"));
Второй — уже существующий, «legacy» JavaScript-файл legacy.js:
function add(a = 0, b = 0) {
return a + b;
}
console.log(add("5", 10));
Оба файла выглядят рабочими, но в каждом спрятана проблема с типами. Дальше разберёмся, при каких условиях компилятор её заметит.
Какие файлы видит tsc
Шаг 1: По умолчанию — только .ts и .tsx
Без дополнительных флагов TypeScript ориентирован исключительно на .ts и .tsx. Файлы с расширением .js в компиляцию проекта не включаются — компилятор их просто не видит.
Шаг 2: Подключаем .js через allowJs и checkJs
Чтобы TypeScript начал заглядывать в JavaScript-файлы, нужны два флага: --allowJs разрешает включать .js-файлы в компиляцию, а --checkJs заставляет их ещё и проверять на ошибки типов — по сути, это то же самое, что добавить // @ts-check в начало файла. Попробуйте:
npx tsc legacy.js --allowJs --checkJs
Вместо ожидаемой ошибки типов вы увидите совсем другую:
error TS5055: Cannot write file 'legacy.js' because it would overwrite input file.
Компилятор пытается не только проверить файл, но и по привычке скомпилировать его — а результат хочет записать в тот же legacy.js, который читает как исходник. Отсюда и следующий флаг.
Куда деваются файлы на выходе
Шаг 3: Обычная компиляция создаёт .js
Скомпилируйте app.ts обычным способом:
npx tsc app.ts
Рядом появится файл app.js — это стандартное поведение tsc: читать .ts, создавать .js.
Шаг 4: —noEmit — только проверка, без файлов
Теперь вернёмся к legacy.js и добавим флаг, который решает проблему из шага 2 — он запрещает компилятору создавать какие-либо файлы вообще, оставляя только проверку типов:
npx tsc legacy.js --allowJs --checkJs --noEmit
На этот раз ошибка именно та, которую мы ожидали:
legacy.js:5:18 - error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
5 console.log(add("5", 10));
~~~
Found 1 error in legacy.js:5
Так как оба параметра a и b имеют значения по умолчанию 0, TypeScript вывел для них тип number — и передача строки "5" сразу стала ошибкой.
Если проект уже собирается через Vite, esbuild или webpack, не заставляйте tsc создавать файлы вообще. Вынесите проверку типов в отдельный npm-скрипт, например "typecheck": "tsc --noEmit", и запускайте его в CI — сборкой пусть занимается основной бандлер.
Ужесточаем проверку: флаг --strict
Проверьте app.ts без дополнительных флагов:
npx tsc app.ts --noEmit
Ошибок нет, хотя параметр value в функции getLength вообще не типизирован. Добавьте --strict:
npx tsc app.ts --noEmit --strict
Теперь компилятор возражает:
app.ts:1:21 - error TS7006: Parameter 'value' implicitly has an 'any' type.
1 function getLength(value) {
~~~~~
Found 1 error in app.ts:1
--strict — это не один флаг, а целый набор более строгих проверок, включённых разом. Вот некоторые из них:
| Флаг | Что проверяет |
|---|---|
| noImplicitAny | Запрещает неявный тип any у параметров и переменных |
| strictNullChecks | Требует явно учитывать null и undefined |
| strictFunctionTypes | Строже проверяет совместимость типов функций |
| strictPropertyInitialization | Требует инициализировать свойства класса |
Запуск и проверка
Пройдите обе проверки ещё раз, чтобы закрепить результат:
npx tsc app.ts --noEmit --strict
npx tsc legacy.js --allowJs --checkJs --noEmit
Первая команда должна вывести ошибку про неявный any, вторая — ошибку про несовместимый тип аргумента.
Бонус: удобные комбинации флагов
tsc --noEmit --strict— быстрая проверка проекта на CI с максимальной строгостью, без создания файлов.tsc --allowJs --checkJs --noEmit— аудит существующего JavaScript-кода без переименования файлов в.ts.- Добавьте оба варианта в
package.jsonкак отдельные npm-скрипты, чтобы не запоминать флаги каждый раз.
Не обязательно сразу переименовывать все .js-файлы в .ts, чтобы начать получать пользу от TypeScript. Включите allowJs и checkJs в tsconfig.json — и компилятор начнёт проверять существующий JavaScript уже сегодня, без единой миграции.
Итог
В этом уроке мы разобрались, как настраивать вход и выход компилятора:
- По умолчанию
tscчитает только.tsи.tsx— для.jsнужны--allowJsи--checkJs. - Если входной и выходной файл совпадают, компилятор отказывается их перезаписывать — на помощь приходит
--noEmit. --noEmitудобен, когда проверка типов не должна создавать файлы — например, в CI или рядом со сторонним бандлером.--strictвключает набор более строгих проверок разом, включая запрет неявногоany.
В следующем уроке разберём ещё один важный параметр компиляции — target, который определяет, под какую версию JavaScript адаптируется ваш код.