Содержание

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

Разберём, что даёт TypeScript бизнесу, во что обходится переход и как его провести без остановки разработки.

Что TypeScript даёт продукту?

TypeScript даёт продукту раннее обнаружение ошибок и понятный код: компилятор проверяет, что функции получают данные нужной формы, до того как код попадёт к пользователю. В большом проекте это заметно снижает число ошибок вида «undefined is not a function» и «не то поле из API».

Практические выгоды:

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

Во что обходится переход на TypeScript?

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

Статья затрат Что включает Как снизить
Настройка сборки tsconfig, линтер, проверки в CI Современные сборщики поддерживают TS из коробки
Типы для API Описание ответов сервера Генерация типов из спецификации OpenAPI
Типизация старого кода Добавление типов в существующие файлы Постепенно, начиная с общих модулей
Обучение команды Базовые типы, дженерики, сужение типов Код-ревью и общие соглашения
Строгость Включение строгих проверок Поэтапно, флаг за флагом

Самая большая экономия — генерация типов из описания API: фронтенд и бэкенд перестают расходиться, а изменения контракта сразу видны при сборке. Как описывать API, мы разбирали в статье как спроектировать REST API.

Монитор и ноутбук с программным кодом Фото: Unsplash

Как перейти на TypeScript постепенно?

Перейти постепенно можно, разрешив в проекте одновременно JavaScript и TypeScript: новые файлы пишутся на TS, старые переводятся по мере изменения. Строгость проверок включается не сразу, а по мере того, как код её выдерживает.

План перехода, который мы используем:

  1. Добавить tsconfig.json с разрешением JS-файлов и мягкими настройками.
  2. Писать весь новый код на TypeScript.
  3. Сгенерировать типы для API и начать использовать их в запросах.
  4. Переводить старые файлы, когда их всё равно нужно менять, начиная с общих утилит и сторов.
  5. Включать строгие флаги по одному и исправлять ошибки.
  6. Добавить проверку типов в CI, чтобы сборка падала при ошибках.

Стартовая конфигурация для постепенного перехода:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "allowJs": true,
    "checkJs": false,
    "strict": false,
    "noImplicitAny": false,
    "skipLibCheck": true
  },
  "include": ["src"]
}

Что включать дальше

Когда большая часть кода переведена, включайте strict: true. Самый полезный флаг внутри него — strictNullChecks: он заставляет обрабатывать случаи, когда значения может не быть, а именно они чаще всего приводят к ошибкам в продакшене.

Как писать типы, чтобы они помогали, а не мешали?

Типы помогают, когда описывают реальную форму данных и границы системы, и мешают, когда превращаются в головоломку ради головоломки. Главное правило — строго типизировать входы и выходы модулей, а внутри доверять выводу типов.

Пример: тип ответа API и функция, которая с ним работает.

type OrderStatus = 'new' | 'paid' | 'shipped' | 'cancelled'

interface Order {
  id: number
  status: OrderStatus
  total: { amount: number; currency: 'RUB' | 'USD' }
  paidAt: string | null
}

function statusLabel(order: Order): string {
  switch (order.status) {
    case 'new': return 'Новый'
    case 'paid': return 'Оплачен'
    case 'shipped': return 'Отправлен'
    case 'cancelled': return 'Отменён'
  }
}

Если на бэкенде появится новый статус и тип обновится, компилятор укажет, что функция его не обрабатывает. Без TypeScript эту ошибку нашёл бы пользователь.

Чего избегать:

  • any как способа «заглушить» компилятор — лучше unknown и явная проверка;
  • дублирования типов вручную там, где их можно сгенерировать;
  • сложных условных типов в прикладном коде, который будут читать все.

Когда TypeScript не нужен?

TypeScript не нужен, когда код живёт недолго или его очень мало: прототип на выброс, лендинг с парой скриптов, одноразовая промо-страница. Там затраты на настройку не окупятся.

Он также не заменяет тесты: TypeScript проверяет форму данных, но не бизнес-логику. Правильный тип у суммы заказа не гарантирует, что скидка посчитана верно.

Для выбора фреймворка это тоже не аргумент: и Vue, и React одинаково хорошо работают с TypeScript — подробнее в статье Vue или React.

Коротко

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

Частые вопросы

  • Замедляет ли TypeScript работу сайта?

    Нет. Типы существуют только на этапе разработки и сборки, а в браузер уходит обычный JavaScript. На скорость сайта TypeScript не влияет.

  • Замедляет ли TypeScript разработку?

    В первые недели — немного, пока команда привыкает и описывает данные. Дальше разработка обычно ускоряется за счёт подсказок редактора, безопасного рефакторинга и меньшего числа ошибок на тестировании.

  • Нужен ли TypeScript на бэкенде на Node.js?

    Для серьёзного бэкенда — да, по тем же причинам, что и на фронтенде. Бонус — общие типы между фронтендом и бэкендом, если оба написаны на TypeScript.