TS модули и пространства имён
Модули в TypeScript — файлы с
import/export(стандарт ES modules), разделяющие область видимости; пространства имён (namespace) — устаревший способ группировки кода внутри одного файла, заменённый модулями.
Зачем нужно
- ES modules — единственный стандартный способ изоляции кода в современном JavaScript/TypeScript
- Правильная настройка
moduleиmoduleResolutionв tsconfig критична для работы с bundler и Node.js - Понимание re-export, barrel-файлов и path aliases необходимо для организации больших кодовых баз
Где используется
- Любой TypeScript-проект — вся кодовая база состоит из модулей
- Библиотеки — публичный API через barrel-файлы (
index.ts) - Monorepo — cross-package импорты через path aliases
- Декларационные файлы
.d.ts— типы для JS-библиотек
Основной контент
Экспорт и импорт (ES modules)
// math.ts — named exports
export function add(a: number, b: number): number { return a + b; }
export function multiply(a: number, b: number): number { return a * b; }
export const PI = 3.14159;
// Можно экспортировать через отдельный export
function divide(a: number, b: number): number { return a / b; }
export { divide };
// main.ts — named imports
import { add, PI } from "./math";
import { divide as div } from "./math"; // переименование
import * as Math from "./math"; // namespace import
Math.add(1, 2);
Math.PI;
Default export
// user-service.ts
export default class UserService {
getUser(id: number): Promise<User> { /* ... */ }
}
// Или функция
export default function createStore() { /* ... */ }
// Импорт — имя может быть любым
import UserService from "./user-service";
import createStore from "./store";
// Default + named в одном файле (разрешено, но не рекомендуется)
export default UserService;
export type { UserConfig };
Barrel-файлы (index.ts)
// features/auth/index.ts — публичный API модуля
export { AuthService } from "./auth-service";
export { LoginForm } from "./login-form";
export type { AuthState, AuthConfig } from "./types";
// Теперь импорт короче
import { AuthService, LoginForm } from "@/features/auth";
// вместо
import { AuthService } from "@/features/auth/auth-service";
import { LoginForm } from "@/features/auth/login-form";
Path aliases в tsconfig
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"],
"@api/*": ["src/api/*"]
}
}
}
// Вместо относительных путей
import { Button } from "../../../components/Button";
// Через алиас
import { Button } from "@components/Button";
Настройка module в tsconfig
{
"compilerOptions": {
"module": "ESNext", // для bundler (Vite, webpack)
"moduleResolution": "bundler", // для современных bundler
// ИЛИ
"module": "NodeNext", // для Node.js ESM
"moduleResolution": "NodeNext"
}
}
namespace (устаревший подход)
// Использовался до ES modules — сейчас не рекомендуется
namespace Validation {
export interface StringValidator {
isAcceptable(s: string): boolean;
}
export class EmailValidator implements StringValidator {
isAcceptable(s: string): boolean {
return /\S+@\S+\.\S+/.test(s);
}
}
}
const validator = new Validation.EmailValidator;
// Современный эквивалент — обычный модуль validation.ts
Типы для сторонних JS-библиотек
// Создание .d.ts для JS-библиотеки без типов
// custom-lib.d.ts
declare module "custom-lib" {
export function process(data: string): string;
export interface Options {
timeout: number;
}
}
// Расширение существующих типов (declaration merging)
declare module "express" {
interface Request {
user?: User; // добавляем кастомное поле
}
}
Частые ошибки
- Смешивать CommonJS (
require) и ESM (import) — TypeScript поддерживает оба, но нельзя мешать в одном файле безesModuleInterop - Circular imports — файл A импортирует из B, B импортирует из A; обычно решается выносом общего кода в C
- Неверный
moduleResolution—"node"не понимаетexportsfield в package.json; для современных проектов нужен"bundler"или"NodeNext" - Barrel-файлы с re-export всего —
export * from "./module"в каждом файле нарушает tree-shaking - Использовать
namespaceв новом коде — предпочтительны ES modules;namespaceоставить только для declaration merging