Модули в TypeScript
TypeScript использует те же модули, что и современный JavaScript (ES-модули). Один файл — один модуль.
Именованный экспорт
// math.ts
export function add(a: number, b: number): number {
return a + b;
}
export const PI = 3.14;
// Можно собрать в одном export
export { add, PI };
// main.ts
import { add, PI } from "./math";
console.log(add(2, 3));
console.log(PI);
Экспорт по умолчанию (default)
Один на модуль. Удобен для главной сущности файла:
// logger.ts
export default function log(message: string): void {
console.log(message);
}
// Имя при импорте может быть любым
import log from "./logger";
import printMessage from "./logger"; // тоже OK
Реальный пример: структура API-клиента
// api/types.ts
export interface User {
id: number;
name: string;
email: string;
}
// api/client.ts
import type { User } from "./types";
export async function fetchUser(id: number): Promise<User> {
const res = await fetch(`/api/users/${id}`);
return res.json();
}
// index.ts
import { fetchUser } from "./api/client";
import type { User } from "./api/types";
const user = await fetchUser(1);
import type — только для типа
Конструкция import type подчёркивает, что импорт нужен только
для TypeScript и будет удалён при компиляции:
// Только тип — попадёт в финальный JS
import type { User } from "./types";
// Значение — останется в JS
import { fetchUser } from "./client";
Re-export и barrel-файлы
Чтобы упростить импорты, используют index.ts, который
переэкспортирует всё наружу:
// api/index.ts
export * from "./types";
export * from "./client";
export * from "./users";
// теперь из другого места — коротко
import { fetchUser, type User } from "./api";
Файл tsconfig.json
Конфигурация компилятора. Инициализация шаблона:
tsc --init
Минимальный полезный tsconfig.json для проекта:
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "node",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
Ключевые флаги
| Флаг | Назначение |
|---|---|
target | Версия JS, в которую компилировать (ES2020, ESNext и т. д.). |
module | Система модулей в выводе (CommonJS, ESNext). |
moduleResolution | Алгоритм разрешения импортов (node, bundler). |
outDir | Куда складывать .js-файлы. |
rootDir | Корневая папка исходников. |
strict | Включает все строгие проверки (рекомендуется). |
noImplicitAny | Запрещает неявный any. |
strictNullChecks | Различает null/undefined от обычных типов. |
noUnusedLocals | Ошибка на неиспользуемые переменные. |
noUnusedParameters | Ошибка на неиспользуемые параметры. |
esModuleInterop | Корректная работа с CommonJS-импортами. |
skipLibCheck | Пропускать проверку типов в .d.ts (ускоряет сборку). |
Флаг strict — что включает
Включение strict: true активирует сразу несколько проверок:
noImplicitAnystrictNullChecksstrictFunctionTypesstrictBindCallApplystrictPropertyInitializationnoImplicitThisalwaysStrict
Для новых проектов всегда включайте strict: true. Для миграции
существующего JS-проекта — можно начать без него и включать постепенно.
Компиляция и наблюдение
tsc # одноразовая компиляция в outDir
tsc --watch # пересборка при изменениях (режим разработки)
tsc --noEmit # только проверка типов, без выдачи JS (для CI)
В package.json удобно вынести это в скрипты:
{
"scripts": {
"build": "tsc",
"dev": "tsc --watch",
"typecheck": "tsc --noEmit",
"start": "node dist/index.js"
}
}
Source maps для отладки
Чтобы при отладке видеть оригинальный TypeScript, а не сгенерированный JS, включают source maps:
{
"compilerOptions": {
"sourceMap": true
}
}
Сторонние библиотеки и типы
Многие библиотеки уже содержат собственные типы (например, axios,
zod). Если типов нет — их ищут в репозитории
@types/* (DefinitelyTyped):
npm install lodash
npm install --save-dev @types/lodash
После этого можно импортировать и получать подсказки:
import _ from "lodash";
const sorted = _.sortBy([{ x: 2 }, { x: 1 }], "x");
Если типов нет вообще
Можно создать файл декларации globals.d.ts:
// Подсказываем TypeScript про сторонний модуль без типов
declare module "untyped-lib" {
export function doStuff(value: unknown): void;
}
Сборка проектов и project references
В монорепозиториях или крупных проектах используют project references —
каждый подпроект имеет свой tsconfig.json, а корневой связывает их:
// tsconfig.json (корень)
{
"files": [],
"references": [
{ "path": "./packages/shared" },
{ "path": "./packages/api" },
{ "path": "./packages/frontend" }
]
}
Это позволяет инкрементально пересобирать только изменившиеся части и изолировать зависимости между пакетами.
Кейс: типичный backend-проект (NestJS-стиль)
project/
├── src/
│ ├── users/
│ │ ├── users.controller.ts # обработчики HTTP
│ │ ├── users.service.ts # бизнес-логика
│ │ ├── users.repository.ts # работа с БД
│ │ └── dto/
│ │ ├── create-user.dto.ts
│ │ └── update-user.dto.ts
│ ├── common/
│ │ └── types.ts
│ ├── app.module.ts
│ └── main.ts
├── test/
├── package.json
└── tsconfig.json
Скрипты для такого проекта:
{
"scripts": {
"build": "tsc",
"start": "node dist/main.js",
"start:dev": "ts-node-dev --respawn src/main.ts",
"typecheck": "tsc --noEmit",
"test": "jest",
"lint": "eslint src --ext .ts"
}
}
Типичные ошибки
1. Cannot find module './types' без расширения
В новых версиях TS и ESM-режиме нужно либо указать расширение, либо
правильно настроить moduleResolution:
// Современный ESM-подход
import { User } from "./types.js"; // расширение .js даже для .ts-файла
2. Не включён strict с самого начала
Включить строгий режим позже в большом проекте — больно. Лучше сразу
"strict": true.
3. Компиляция тестовых файлов в production-вывод
{
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "**/*.test.ts"]
}
4. Забыли @types/...
Библиотека установлена, но TS ругается — обычно не хватает пакета типов.
Проверяйте поле types или typings в
package.json библиотеки.
Практика
- Создайте проект из двух файлов:
math.tsс экспортируемой функцией иmain.ts, который её импортирует. - Инициализируйте
tsconfig.jsonчерезtsc --initи настройтеstrict: true,outDir,rootDir. - Добавьте скрипты
build,dev,typecheckвpackage.json. - Установите библиотеку без встроенных типов (например,
lodash) и добавьте@types/lodash. - Включите
noUnusedLocalsи убедитесь, что неиспользуемая переменная вызывает ошибку.
Итог
Мы разобрались со структурой модулей, импортами/экспортами и
import type, изучили ключевые опции tsconfig.json
и флаги компилятора, поняли, как подключать сторонние библиотеки и их типы,
и рассмотрели структуру реального проекта. В следующей главе — применение
TypeScript на практике: объединения, литеральные типы, type guards и
utility-типы.
Комментарии 0
Пока нет комментариев. Станьте первым!