Конфигурация и миграция

Что это такое

Поведением TypeScript управляет файл tsconfig.json: какие файлы проверяются, какие языковые возможности разрешены, насколько строго проверяются типы и какой JavaScript выдаётся на выходе. Миграцией называют добавление такого файла в существующий проект на JavaScript без остановки работы над новыми возможностями.

Почему это важно

Параметры компилятора решают, будет система типов активом или формальностью. Проект с выключенным strict получает подсветку синтаксиса и почти ничего больше, а тот же проект с включённым находит настоящие дефекты в коде, который работает не первый год. На практике сложнее миграция, потому что большую нетипизированную кодовую базу нельзя перевести одним коммитом: проверки нужно вводить постепенно, в таком порядке, который сохраняет сборку зелёной, а команду — незаблокированной; команды, которые этого не планируют, либо оставляют strict выключенным навсегда, либо проводят неделю со сломанной сборкой.

Ключевые идеи

Включайте строгость для нового кода

Важнее всего параметры strict, noUncheckedIndexedAccess и exactOptionalPropertyTypes. Включить их сразу для всего старого проекта часто невозможно, зато включить их для файлов, которые уже типизированы, ничего не стоит и не даёт копиться новому долгу.

{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "noEmit": true
  },
  "include": ["src/**/*.ts"]
}

noEmit обычно верен для фронтенд-проекта: код компилирует сборщик, а задача TypeScript — только проверять его.

skipLibCheck — прагматичный выбор по умолчанию

Он пропускает проверку файлов объявлений зависимостей, которые часто написаны для другой версии компилятора. Изредка он скрывает настоящие проблемы; на практике он убирает много ложных.

Разрешайте и запрещайте JavaScript явно

allowJs позволяет компилятору обрабатывать файлы JavaScript, а checkJs заставляет его проверять их типы. Один только allowJs даёт импортам из нетипизированных файлов разрешаться без проверки их содержимого — полезный промежуточный шаг во время миграции.

Мигрируйте, расширяя границу

Практический путь — растущий список include: добавляйте файлы TypeScript, держите их строгими и позволяйте им импортировать JavaScript. Сначала дайте явные типы общим границам — клиентам API, моделям данных, — потому что эти типы распространяются наружу и удешевляют перевод остального.

Проверяйте типы в CI, а не только в редакторе

Ошибка, которая видна только на машине того, кто последним запускал компилятор, — это не принуждение. Аннотации остаются правдивыми только благодаря шагу tsc --noEmit в конвейере.

Практика

Включите один строгий параметр и разберите последствия

Возьмите существующий проект, включите один строгий параметр и исправьте все ошибки, которые он породит, не добавляя any.

Готово, когда: компилятор сообщает ноль ошибок, в диффе нет новых any, и вы можете назвать один настоящий дефект, который параметр выявил.

Переведите один модуль и закрепите границу

Переведите один модуль из файла JavaScript на TypeScript, типизируйте его публичные экспорты и добавьте в сборку шаг tsc --noEmit.

Готово, когда: модуль чисто импортируется из оставшегося JavaScript, его экспортируемые типы используются в месте вызова без приведений, а сборка падает, если кто-то их нарушит.

Частые ошибки

  • strict выключен бессрочно — аннотации типов описывают замысел, но ничто его не проверяет; исправить: включите его для новых каталогов сейчас, а старые переводите следом.
  • Перевод всего репозитория в одной ветке — ветка живёт неделями, конфликты накапливаются, и работу бросают; исправить: переводите файл за файлом, сохраняя сборку зелёной на всём протяжении.
  • any, чтобы первая миграция скомпилировалась — код выглядит типизированным, но до него не доходит ни одна проверка; исправить: используйте unknown на настоящих границах и сужайте в месте применения.
  • Проверка типов только в редакторе — нетипизированный файл попадает в main, и сборка ломается у следующего человека; исправить: запускайте tsc --noEmit в CI.
  • target ниже, чем нужно вашим браузерам — вывод остаётся многословным, и старый синтаксис сохраняется без надобности; исправить: задайте target по реальной матрице поддержки.

Что читать дальше

  • Обобщения (02-frontend/19-typescript/03-generics) — утилитарные типы и вывод — инструменты, к которым вы тянетесь, исправляя ошибки строгого режима.
  • Управление пакетами (npm) (02-frontend/04-package-management-npm) — откуда берутся компилятор и его пакеты типов и как фиксируются версии.
  • CI/CD (06-cloud-devops/08-ci-cd) — место, где должна стоять проверка tsc --noEmit.