Back

TypeScript в Node: Практическая настройка

TypeScript в Node: Практическая настройка

Вы уже пишете на TypeScript для браузера. Теперь вам нужно запустить его на серверной стороне — для API, скрипта сборки или SSR. Проблема: большинство руководств по настройке устарели и рекомендуют конфигурации CommonJS или инструменты, которые не соответствуют современному Node.js.

Это руководство охватывает два подхода к настройке TypeScript в Node.js: компиляция с помощью tsc и запуск JavaScript, или прямой запуск .ts файлов с использованием встроенного удаления типов Node. Оба подхода работают. Каждый подходит для разных сценариев.

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

  • Установите "type": "module" в package.json для включения ESM по умолчанию в современных проектах TypeScript Node.js
  • Используйте компиляцию tsc для production-развертываний, публикуемых пакетов и кода, использующего enums, namespaces или parameter properties
  • Используйте встроенное удаление типов Node для локальных скриптов, серверов разработки и быстрых прототипов
  • Всегда используйте import type для импорта только типов, чтобы избежать ошибок во время выполнения при удалении типов
  • Запускайте tsc --noEmit в CI, поскольку удаление типов Node не выполняет проверку типов

Базовая настройка: Node 24 LTS и ESM

Начните с этой основы:

{
  "type": "module"
}

Это включает ESM по умолчанию. Ваши импорты используют синтаксис ESM, и Node разрешает модули соответствующим образом.

Node 24 — это текущая базовая версия LTS для этой настройки (можно скачать здесь: https://nodejs.org/en/download).

Подход 1: Компиляция с tsc, запуск JavaScript

Этот подход разделяет компиляцию и выполнение. Используйте его для production-развертываний, публикуемых пакетов или когда вам нужна полная поддержка возможностей TypeScript.

tsconfig для Node 24

{
  "compilerOptions": {
    "target": "ES2024",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "rootDir": "src",
    "outDir": "dist",
    "strict": true,
    "skipLibCheck": true,
    "declaration": true,
    "sourceMap": true,
    "verbatimModuleSyntax": true,
    "isolatedModules": true,
    "lib": ["ES2024"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}

Ключевые настройки в этой конфигурации:

  • module: NodeNext и moduleResolution: NodeNext: Соответствует фактическому поведению разрешения модулей Node
  • verbatimModuleSyntax: Требует явного import type для импорта только типов — критически важно для избежания ошибок во время выполнения (см. документацию TypeScript: https://www.typescriptlang.org/tsconfig#verbatimModuleSyntax)
  • isolatedModules: Обеспечивает совместимость с инструментами транспиляции отдельных файлов

Скрипты

{
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js",
    "dev": "tsc --watch"
  }
}

Запустите npm run build, затем npm start. Скомпилированный JavaScript находится в dist/.

Подход 2: Встроенная поддержка TypeScript в Node (удаление типов)

Node представил встроенную поддержку TypeScript в Node 22 и стабилизировал её в Node 24 LTS через удаление типов. Используйте её для скриптов, локальных инструментов или разработки, когда вы хотите избежать этапов сборки.

Официальная документация: https://nodejs.org/api/typescript.html

Как это работает

В Node 24+ запускайте напрямую:

node src/index.ts

(Старые версии Node требовали экспериментальных флагов; Node 24 не требует.)

Критические ограничения

Встроенная поддержка TypeScript в Node только удаляет типы — она не проверяет типы. Вам всё ещё нужен tsc --noEmit в CI или в вашем редакторе для обнаружения ошибок.

Другие ограничения:

  • Игнорирует tsconfig.json: Node не читает ваши опции компилятора
  • Требует явных расширений файлов: Пишите import { foo } from './utils.js' даже когда исходный файл — utils.ts
  • Соблюдает правила ESM и CJS: Поле type в вашем package.json имеет значение
  • Не запускает TypeScript из node_modules: Зависимости должны быть скомпилированным JavaScript
  • Поддерживает только удаляемый синтаксис: Enums, namespaces и parameter properties не работают, если не включить --experimental-transform-types

Расширения файлов имеют значение

Для смешанных форматов модулей:

  • .mts файлы → всегда ESM
  • .cts файлы → всегда CommonJS
  • .ts файлы → следуют полю type в package.json

Избежание ошибок во время выполнения

Используйте import type для импорта только типов:

// Правильно
import type { Request, Response } from 'express'
import express from 'express'

// Неправильно - приведёт к ошибке во время выполнения при удалении типов
import { Request, Response } from 'express'

Включите verbatimModuleSyntax в вашем tsconfig, чтобы отлавливать это во время разработки, даже если Node игнорирует конфигурацию во время выполнения.

Какой подход использовать

Используйте компиляцию tsc для:

  • Production-развертываний
  • Публикуемых npm-пакетов
  • Кода, использующего enums, namespaces или parameter properties
  • Проектов, требующих source maps в production

Используйте встроенное удаление типов для:

  • Локальных скриптов и инструментов
  • Серверов разработки (в паре с --watch)
  • Быстрых прототипов
  • Сборок разработки SSR

Практическая настройка для разработки

Комбинируйте оба подхода:

{
  "scripts": {
    "dev": "node --watch src/index.ts",
    "typecheck": "tsc --noEmit",
    "build": "tsc",
    "start": "node dist/index.js"
  }
}

Разработка использует встроенное выполнение для скорости. CI запускает typecheck. Production развертывает скомпилированный JavaScript.

Заключение

Современная настройка TypeScript в Node.js проще, чем предполагают старые руководства. Используйте ESM, настройте разрешение модулей NodeNext и выбирайте стратегию выполнения в зависимости от контекста. Встроенное удаление типов работает для разработки и скриптов. Скомпилированный вывод работает для production и пакетов. Оба подхода используют один и тот же исходный код и tsconfig — вы не привязаны ни к одному из них.

Часто задаваемые вопросы

Разрешение модулей Node требует явных расширений файлов для ESM. Когда вы пишете import from ./utils.js, Node ищет именно этот путь во время выполнения, даже если ваш исходный файл — utils.ts. Поскольку удаление типов убирает типы, но не переименовывает файлы, а tsc выводит .js файлы, использование расширений .js в вашем исходном коде гарантирует, что импорты работают в обоих сценариях.

Не по умолчанию. Enums требуют трансформации кода, а не просто удаления типов. Вы можете включить флаг --experimental-transform-types для поддержки enums, namespaces и parameter properties, но это добавляет сложности. Для более простых настроек рассмотрите использование const-объектов с утверждениями as const в качестве альтернативы enums.

Для большинства случаев использования — нет. Встроенное удаление типов Node 24 обрабатывает прямое выполнение .ts. Инструменты вроде ts-node и tsx — это опциональные удобства, которые добавляют поддержку tsconfig.json, разрешение псевдонимов путей и полные трансформации TypeScript без флагов. Используйте их только если вашей настройке нужны эти возможности.

При использовании встроенного удаления типов Node выполняет ваши .ts файлы напрямую, поэтому номера строк в трассировках стека соответствуют вашему исходному коду. Для скомпилированного кода включите sourceMap в tsconfig.json, и Node автоматически будет использовать .js.map файлы для отображения исходных местоположений TypeScript в ошибках и сеансах отладки.

Complete picture for complete understanding

Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.

Check our GitHub repo and join the thousands of developers in our community.

OpenReplay