Module Augmentation

Module Augmentation — механизм TypeScript, позволяющий дополнять существующие объявления типов модулей или глобального пространства имён из внешнего файла без изменения исходного кода библиотеки.

Зачем нужно

Сторонние библиотеки иногда позволяют добавлять свойства в свои объекты через middleware или плагины. Module augmentation позволяет отразить это расширение в системе типов без форка @types пакета, что сохраняет типобезопасность в проектах с кастомными расширениями.

Где используется

  • Добавление req.user к Express Request через middleware
  • Расширение типов process.env для конкретного проекта
  • Добавление свойств к Window или globalThis
  • Дополнение типов библиотек (Vue, axios, Fastify)
  • Declaration merging для интерфейсов из npm-пакетов

Основной контент

Базовый синтаксис

Файл должен быть модулем (содержать import или export). Используется блок declare module "имя-модуля".

// src/types/express.d.ts
import { User } from "../models/user";

declare module "express-serve-static-core" {
  interface Request {
    user?: User;
    correlationId: string;
  }
}

// Теперь в маршрутах:
app.get("/profile", (req, res) => {
  if (req.user) {
    res.json(req.user.name); // TypeScript знает тип user
  }
});

Расширение process.env

// src/types/env.d.ts
declare namespace NodeJS {
  interface ProcessEnv {
    NODE_ENV: "development" | "production" | "test";
    DATABASE_URL: string;
    PORT?: string;
    JWT_SECRET: string;
  }
}

// В коде:
const dbUrl = process.env.DATABASE_URL; // string (не undefined)
const port  = process.env.PORT ?? "3000"; // string | undefined → string

Расширение Window

// src/types/global.d.ts
export {}; // делаем файл модулем

declare global {
  interface Window {
    analytics: {
      track(event: string, data?: Record<string, unknown>): void;
    };
    __APP_VERSION__: string;
  }
}

// В браузерном коде:
window.analytics.track("page_view", { path: location.pathname });
console.log(window.__APP_VERSION__);

Declaration merging — добавление к существующему интерфейсу

// Из библиотеки: interface Theme { colors: { primary: string } }

// В нашем коде:
import "some-ui-library";

declare module "some-ui-library" {
  interface Theme {
    spacing: { sm: number; md: number; lg: number };
  }
}

// Теперь Theme содержит оба набора свойств
const theme: Theme = {
  colors: { primary: "#fff" },
  spacing: { sm: 4, md: 8, lg: 16 },
};

Настройка tsconfig.json для augmentation

{
  "compilerOptions": {
    "typeRoots": ["./src/types", "./node_modules/@types"]
  },
  "include": ["src/**/*"]
}

Частые ошибки

  • Файл не является модулем — без import/export augmentation не работает; добавьте export {} если нет других экспортов.
  • Использовать interface вместо namespace NodeJS — для process.env нужно declare namespace NodeJS { interface ProcessEnv }.
  • Augmentation не подхватывается — убедитесь что файл включён в tsconfig.json через include или typeRoots.
  • Augmenting type aliases — работает только с interface и namespace; type нельзя дополнить через declaration merging.

Связанные темы

Ресурсы