Namespace (przestrzeń nazw) to mechanizm organizacji kodu, który pojawił się jeszcze w czasach kodu pre-ES6, służący do łączenia logicznie powiązanych encji. Pomaga w strukturyzacji dużych projektów, grupując klasy, funkcje, interfejsy i typy w ramach jednej przestrzeni nazw, aby uniknąć konfliktów nazw i uczynić kod bardziej czytelnym.
Historia: Przed wprowadzeniem standardów JavaScript ES6, programiści używali IIFE, obiektów i przestrzeni nazw, aby imitować modularność. TypeScript wprowadził słowo kluczowe namespace (wcześniej internal module) do grupowania kodu.
Problem: Nowoczesne moduły (ES6 Module) stały się standardem, a oba podejścia (namespace i moduł) istnieją równolegle, co powoduje konfuzję przy projektowaniu architektury — kiedy lepiej używać namespace, a kiedy module?
Rozwiązanie: Namespace nadal są użyteczne do łączenia funkcji pomocniczych i typów w czysto TypeScriptowych projektach (np. przy generowaniu pojedynczych plików JS poprzez outFile). Do dzielenia kodu między plikami, szczególnie przy pracy z npm i nowoczesnymi bundlerami, lepiej jest używać modułów. Namespace często są stosowane w wewnętrznych bibliotekach, deklaracjach typów oraz w sytuacjach, gdy potrzebna jest strukturyzacja w obrębie jednego pliku lub w starym kodzie.
Przykład kodu:
namespace MyMath { export function add(a: number, b: number) { return a + b; } } console.log(MyMath.add(2, 3)); // 5
Kluczowe cechy:
Czy łącząc namespace z różnych plików, uzyskamy jedną namespace czy kilka?
TypeScript wykonuje scalanie rady deklaracji — przy pasujących nazwach różne części przestrzeni nazw są scalane w jedno, jeśli są prawidłowo podłączone i znajdują się w tej samej przestrzeni zasięgu.
// 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; } } // Po kompilacji MathUtil zawiera obie metody
Czy można używać import/require dla namespace jak dla modułu?
Nie, namespace nie ma eksportu domyślnego/nazwanego, nie można go zaimportować standardową składnią ES6. Namespace to czysto koncept TypeScript, który nie jest przenoszony na moduły JavaScript.
Czy można importować wartości z namespace do innego pliku za pomocą import?
Nie, aby uzyskać dostęp do namespace z innych plików, konieczne jest użycie referencji (/// <reference path="..." />) lub kompilacja z outFile, import przez import jest niemożliwy.
W starym projekcie podzielono logikę na dziesiątki namespace, te same nazwy pojawiły się w kilku plikach, co czasami prowadziło do nieoczekiwanego scalania lub konfliktów. Przy przechodzeniu na architekturę modułową przeniesienie kodu stało się bardzo pracochłonne.
Plusy:
Minusy:
W dużej bibliotece zadeklarowano API poprzez deklaracje namespace w jednym pliku index.d.ts, ujednolicając wszystkie typy i interfejsy bez implementacji kodu. Umożliwiło to szybkie typowanie konsumentów biblioteki i łatwą aktualizację kontraktów między zespołami.
Plusy:
Minusy: