Namespace (пространство имён) — это механизм организации кода, который появился ещё во времена pre-ES6 кода для объединения логически связанных сущностей. Он помогает структурировать большие проекты, группируя классы, функции, интерфейсы и типы внутри единого пространства имён, чтобы избежать конфликтов имён и сделать код более читаемым.
История вопроса: до появления стандартов JavaScript ES6 разработчики использовали IIFE, объекты и пространства имён для имитации модульности. TypeScript ввёл ключевое слово namespace (ранее internal module) для группировки кода.
Проблема: современные модули (ES6 Module) стали стандартом, и оба подхода (namespace и модуль) существуют параллельно, что вызывает путаницу при проектировании архитектуры — когда лучше использовать namespace, а когда module?
Решение: Namespace всё ещё полезны для объединения вспомогательных функций и типов в чисто TypeScript-проектах (например, при генерации единых JS-файлов выводом outFile). Для разделения кода между файлами, особенно при работе с npm и современными сборщиками, правильнее использовать модули. Namespace часто применяются во внутренних библиотеках, декларациях типов и ситуациях, когда необходима структуризация внутри одного файла или в старом коде.
Пример кода:
namespace MyMath { export function add(a: number, b: number) { return a + b; } } console.log(MyMath.add(2, 3)); // 5
Ключевые особенности:
Если объединить namespace из разных файлов, будет ли один namespace или несколько?
TypeScript выполняет слияние declaration merging — при совпадении имени разные части пространства имён объединяются в одно, если корректно подключены и находятся в одной области видимости.
// mathA.ts namespace MathUtil { export function sum(a: number, b: number) { return a + b; } } // mathB.ts namespace MathUtil { export function mul(a: number, b: number) { return a * b; } } // После компиляции MathUtil содержит оба метода
Можно ли использовать import/require для namespace как для модуля?
Нет, у namespace нет экспорта по умолчанию/именного экспорта, его нельзя импортировать стандартным синтаксисом ES6. Namespace — это чисто TypeScript-концепция, которая не транслируется в модули JavaScript.
Можно ли импортировать значения из namespace в другой файл через import?
Нет, для доступа к namespace из других файлов требуется использование reference (/// <reference path="..." />) или компиляция с outFile, импорт через import невозможно.
В старом проекте разбили логику на десятки namespace, одни и те же имена появились в нескольких файлах, что иногда приводило к неожиданному объединению или конфликтам. При переходе на модульную архитектуру перенос кода стал очень трудоёмким.
Плюсы:
Минусы:
В крупной библиотеке объявили API через декларации namespace в одном файле index.d.ts, унифицировав все типы и интерфейсы без кода-реализации. Позволило быстро типизировать потребителей библиотеки и просто обновлять contract между командами.
Плюсы:
Минусы: