Что такое namespace в TypeScript и когда его использовать?
Namespace в TypeScript
Namespace (пространство имён) — механизм TypeScript для логической группировки кода: интерфейсов, классов, функций и переменных. Все члены namespace живут внутри одного именованного объекта, что исключает конфликты имён в глобальной области.
До появления ES-модулей namespace был основным способом структурировать большие TypeScript-проекты. Сейчас его роль значительно сузилась.
Базовый синтаксис
namespace Validation {
// Экспортируем только то, что нужно снаружи
export interface StringValidator {
isAcceptable(s: string): boolean;
}
// Вспомогательное регулярное выражение — скрыто внутри namespace
const lettersRegexp = /^[A-Za-z]+$/;
export class LettersOnlyValidator implements StringValidator {
isAcceptable(s: string): boolean {
return lettersRegexp.test(s);
}
}
}
const validator = new Validation.LettersOnlyValidator();
console.log(validator.isAcceptable('Hello')); // true
Вложенные namespace
namespace App {
export namespace Models {
export interface User {
id: number;
name: string;
}
}
export namespace Services {
export function getUser(id: number): Models.User {
return { id, name: 'Test' };
}
}
}
const user: App.Models.User = App.Services.getUser(1);
Разделение по файлам
Namespace можно распределить по нескольким файлам с директивой /// <reference path="..." />:
// validators/letters.ts
/// <reference path="validators.ts" />
namespace Validation {
export class LettersValidator implements StringValidator {
isAcceptable(s: string) {
return /^[A-Za-z]+$/.test(s);
}
}
}
Алиасы для длинных путей
import StringValidator = Validation.StringValidator;
// Теперь можно писать StringValidator вместо Validation.StringValidator
Когда использовать namespace
Используйте namespace:
- В файлах деклараций
.d.tsдля описания типов глобальных библиотек (jQuery, Google Maps) - В скриптах без модульной системы (браузерные
<script>-теги,outFile-компиляция) - В legacy-проектах, где переход на ES-модули нецелесообразен
- Для аугментации глобальных типов (
declare namespace NodeJS { interface ProcessEnv { ... } })
Не используйте namespace:
- Когда проект уже использует ES-модули (
import/export) — они несовместимы с namespace-подходом - В любом современном Node.js, React или Vue проекте
- Как замену папок и файлов — файловая структура ES-модулей справляется лучше
Namespace vs ES-модули
| Аспект | Namespace | ES-модули |
|---|---|---|
| Стандарт | TypeScript | ECMAScript |
| Загрузка | глобально / outFile | import(), bundler |
| Tree-shaking | нет | есть |
| Рекомендация TS | устарело | предпочтительно |
Итог
Namespace — исторический инструмент TypeScript. В современном коде их почти всегда заменяют ES-модули. Ключевое исключение — типизация глобальных библиотек и .d.ts-файлы, где namespace остаётся стандартной практикой.
Что хочет услышать интервьюер
Понимание, что namespace — это TypeScript-специфичный механизм, не стандарт ECMAScript
Чёткое разграничение: namespace vs ES-модули, и почему сегодня предпочтительны модули
Знание реальных сценариев применения: .d.ts-файлы, глобальные библиотеки, legacy-код
Понимание, что namespace компилируется в IIFE-объект, а не в настоящие модули
Упоминание `declare namespace` для аугментации глобальных типов
Пример: Базовый namespace с инкапсуляцией
// Базовое использование namespace
namespace Validation {
export interface StringValidator {
isAcceptable(s: string): boolean;
}
// Приватная деталь реализации — не экспортируем
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
export class EmailValidator implements StringValidator {
isAcceptable(s: string): boolean {
return emailRegex.test(s);
}
}
}
// Использование снаружи
const validator: Validation.StringValidator = new Validation.EmailValidator();
console.log(validator.isAcceptable('user@example.com')); // true
Пример: Аугментация глобальных типов через declare namespace
// Типичный use-case: аугментация глобальных типов в .d.ts
declare namespace NodeJS {
interface ProcessEnv {
NODE_ENV: 'development' | 'production' | 'test';
DATABASE_URL: string;
PORT?: string;
}
}
// Теперь process.env типизирован
const dbUrl: string = process.env.DATABASE_URL; // без ошибки
const port = process.env.PORT ?? '3000';
Пример: Предпочтительная альтернатива: ES-модули
// Современная альтернатива: ES-модули вместо namespace
// файл: validation/email-validator.ts
export interface StringValidator {
isAcceptable(s: string): boolean;
}
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
export class EmailValidator implements StringValidator {
isAcceptable(s: string): boolean {
return emailRegex.test(s);
}
}
// файл: main.ts
import { EmailValidator, StringValidator } from './validation/email-validator';
const validator: StringValidator = new EmailValidator();
console.log(validator.isAcceptable('user@example.com'));
Типичные ошибки
Использование namespace в проектах с ES-модулями — они конфликтуют между собой
Путаница namespace с ES-модулями: считать, что namespace даёт tree-shaking или lazy-loading
Создание глубоко вложенных namespace вместо нормальной файловой структуры
Не экспортировать члены namespace через `export`, а потом удивляться ошибке доступа
Применение namespace в современном React/Node проекте вместо обычных файлов с export


