Простори імен (namespaces) з'явилися в TypeScript до того, як JavaScript отримав ES-модулі. Вони групують код в іменований об'єкт у глобальній області:
namespace Validation {
export function isEmail(value: string): boolean {
return value.includes('@');
}
}
Validation.isEmail('a@b.ua');
Компілюються в IIFE, що створює об'єкт Validation.
ES-модулі - стандарт JavaScript: файл = модуль, явні import/export, власна область видимості, підтримка браузерами, Node.js і збирачами.
Чому для коду застосунку - модулі, а не namespaces:
- збирачі розуміють залежності між модулями - tree shaking, розділення коду. Простір імен - один об'єкт, з якого нічого не викинеш;
- явні залежності видно з імпортів; простори імен покладаються на порядок підключення файлів;
- стирання типів (Node.js,
erasableSyntaxOnly) не підтримує namespaces з виконуваним кодом - їм потрібна генерація; outFile, що склеював простори імен з багатьох файлів в один, видалено в TypeScript 6.
Де namespaces лишилися доречними:
- у файлах декларацій - для опису бібліотек, що створюють глобальні об'єкти, і для поєднання функції з властивостями (злиття з функцією чи класом);
- простори імен лише з типами (
namespace API { export type User = ... }) - стираються без генерації коду, хоча й тут частіше обходяться модулями; - доповнення глобальних просторів:
declare global { namespace Express { ... } },namespace NodeJS.
Ключове слово module для просторів імен: колись простір імен можна було оголосити як module Foo { }. Згодом з'явилося namespace, а module лише не радили. У TypeScript 6 це стало помилкою з можливістю тимчасово приглушити її, у TypeScript 7 - остаточною помилкою:
module Legacy { } // помилка: використовуйте namespace
namespace Modern { } // правильно
declare module 'some-lib' { } // це інше - ambient-оголошення модуля, і воно підтримується
Причина - можлива пропозиція «module blocks» до стандарту JavaScript, з якою старий синтаксис TypeScript конфліктував би.
Міграція старого коду з просторами імен на модулі зазвичай механічна: кожен простір імен - окремий файл з export, звернення Validation.isEmail - імпорт import { isEmail } from './validation.js' або import * as Validation from ....