Перейти к основному содержимому

Форматы и подключение TypeScript

Разработчику

Дальше: Компиляция · Рекомендации · Справочник — tsconfig


TypeScript не подключают в браузер напрямую: исходники .ts / .tsx проходят компиляцию (tsc) или сборку (Vite, esbuild), на выходе — JavaScript. Настройки живут в tsconfig.json и скриптах package.json.

Маршрут: Первая программаподключениеЭкосистемаКомпиляция.


Три типичных сценария

СценарийИнструментыРезультат
Node.js backendtsc, @types/nodedist/*.js + node dist/index.js
Frontend SPAVite + react-ts / vue-tsdev-server, bundle для браузера
Монорепозиторийtsc -b, project referencesнесколько пакетов с общим base config

Минимальный Node.js-проект

mkdir my-api && cd my-api
npm init -y
npm i -D typescript @types/node
npx tsc --init

package.json (скрипты):

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

tsconfig.json (стартовый вариант для Node 20+):

{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"strict": true,
"outDir": "dist",
"rootDir": "src",
"esModuleInterop": true,
"skipLibCheck": true
},
"include": ["src"]
}

Разбор:

  • module: NodeNext — согласованность с "type": "module" в package.json (ESM) или .cjs (CommonJS).
  • typecheck без emit удобен в CI, когда сборку делает другой инструмент.

Подробный разбор первого запуска — 4.md.


Frontend: Vite + TypeScript

npm create vite@latest my-app -- --template react-ts
cd my-app && npm i && npm run dev

Vite даёт:

  • готовый tsconfig.json и tsconfig.node.json;
  • hot reload;
  • проверку типов через tsc в скрипте build (tsc -b && vite build).

Для Vue: --template vue-ts. Связка с React — 21.md.


tsconfig.json: что настроить в первую очередь

ОпцияНазначение
include / excludeКакие файлы входят в проект
rootDir / outDirОткуда и куда кладётся JS
targetВерсия JS на выходе (ES2022, …)
moduleФормат модулей (NodeNext, ESNext, CommonJS)
libДоступные API (DOM, ES2022 — для браузера)
strictСтрогие проверки — 6.md
jsxreact-jsx для React в .tsx
paths / baseUrlАлиасы импортов

Полная таблица флагов — Справочник — tsconfig и официальный TSConfig Reference.


ESM и CommonJS

Node.js и bundler по-разному трактуют import / require.

ESMCommonJS
Синтаксисimport / exportrequire / module.exports
В package.json"type": "module"по умолчанию или "type": "commonjs"
Расширения.mjs или .js при "type": "module".cjs при смешении

Рекомендация для новых Node-проектов: ESM + "module": "NodeNext" + "moduleResolution": "NodeNext".

Типичная ошибка: Cannot use import statement outside a module — не совпали package.json, расширение файла и module в tsconfig.


Алиасы путей (paths)

{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@shared/*": ["../shared/src/*"]
}
}
}
import { User } from "@/types/user";

Разбор:

  • TypeScript понимает алиасы при проверке типов.
  • Runtime (Node/Vite) должен знать те же пути: в Vite — resolve.alias в vite.config.ts; в Node 20+ — иногда imports в package.json или сборщик.

Типы для npm-пакетов (@types)

JavaScript-библиотека без встроенных .d.ts типизируется через DefinitelyTyped:

npm i -D @types/react @types/node @types/express
СитуацияДействие
Пакет уже поставляет .d.ts@types/* не нужен
Есть только JSnpm i -D @types/имя-пакета
Нет типов нигдесвой declare module "lib"Справочник — декларации

Ошибка Could not find a declaration file for module 'X' — сигнал установить или написать декларацию.


Файлы .ts и .tsx

РасширениеКогда
.tsTypeScript без JSX
.tsxTypeScript + JSX (React и др.)
.d.tsТолько типы, без JS на выходе

import type — импорт только типов (удаляется при компиляции):

import type { User } from "./types";

Монорепозиторий

В корне — tsconfig.base.json с strict и общими путями. В пакетах:

{
"extends": "../../tsconfig.base.json",
"compilerOptions": { "outDir": "dist", "rootDir": "src", "composite": true },
"references": [{ "path": "../shared" }],
"include": ["src"]
}

Сборка графа: tsc -b. Подробнее — Экосистема, Справочник — project references.


Модули ES и пространства имён

Современный TypeScript опирается на ES-модули (import / export). Имена файлов и module / moduleResolution в tsconfig должны совпадать с тем, как код запускается (Node ESM, bundler).

// user.ts
export type User = { id: string; name: string };
export function createUser(name: string): User {
return { id: crypto.randomUUID(), name };
}

// index.ts
import { createUser, type User } from "./user.js";

Разбор:

  • В Node с module: NodeNext в импорте указывают .js, хотя исходник — .ts4.md.
  • export type / import type — только типы, не попадают в runtime emit — 8.md.

Пространства имён (namespace)

namespace Geometry {
export type Point = { x: number; y: number };
export function distance(a: Point, b: Point): number {
return Math.hypot(a.x - b.x, a.y - b.y);
}
}

const p: Geometry.Point = { x: 0, y: 0 };
ES-модулиnamespace
Рекомендация в новом кодедаlegacy, declaration merging, некоторые .d.ts
Файловая границаодин модуль = файл(ы)логическая группа внутри файла
Tree-shakingхорошо с bundlerхуже

В прикладных проектах предпочитайте файлы-модули; namespace встречается в старых библиотеках и при слиянии деклараций. Таблицы — Справочник — модули.


Декларации типов (.d.ts)

Декларация описывает форму API без реализации — для JS-библиотек, глобальных переменных и расширения типов.

Файл global.d.ts в проекте

declare const __APP_VERSION__: string;

declare global {
interface Window {
analytics?: { track(event: string): void };
}
}
export {};

Разбор:

  • declare const — переменная есть в runtime (задаёт bundler), TS знает тип.
  • declare global расширяет Window; export {} делает файл модулем.

Модуль без типов

// types/legacy-lib.d.ts
declare module "legacy-lib" {
export function connect(url: string): Promise<void>;
}

После этого import { connect } from "legacy-lib" типизируется. Источники типов:

ИсточникПример
Пакет с встроенными .d.tsсовременный react
DefinitelyTyped@types/lodash
Свой declare moduleвнутренний legacy JS

Слияние деклараций (declaration merging)

interface User {
id: string;
}

interface User {
name: string;
}
// User = { id: string; name: string }

Работает для interface и namespace — удобно дополнять типы библиотек. Для union и mapped types используйте type, не interface. Подробнее — Справочник — декларации, emit .d.ts15.md.


tsc и bundler: кто за что отвечает

ЗадачаКто
Проверка типовtsc или tsc --noEmit
Транспиляция TS → JStsc или esbuild/swc внутри Vite
Сборка бандла для браузераVite / Webpack
Source mapssourceMap: true в tsconfig + настройки bundler

В CI часто выносят отдельный шаг npm run typecheck (tsc --noEmit): так сборка не пройдёт мимо ошибок типов, даже если bundler не остановился на предупреждениях.


Частые ошибки подключения

СимптомПричинаРешение
Cannot find moduleПуть или moduleResolutionПроверить paths, NodeNext, установлен ли пакет
Нет типов у пакетаНет .d.ts@types/* или declare module
Старый JS в браузереЗавышен target / нет полифиловПонизить синтаксис или настроить bundler
strict выключенНаследие шаблонаВключить в новом коде — 6.md
Смешение ESM/CJSРазные настройки Node и TSВыровнять package.json и module

Практика

  1. Создайте Node-проект с src/index.ts, outDir: dist, скриптами build и typecheck.
  2. Добавьте алиас @/ на src/ и импортируйте тип из src/types.
  3. Установите @types/node и вызовите process.env с подсказкой IDE.
  4. Создайте Vite react-ts и найдите два tsconfig — объясните разницу.
  5. Включите strict: true и исправьте все новые ошибки в одном файле.

Смежные статьи