Ein Namespace (Namensraum) ist ein Mechanismus zur Organisation von Code, der bereits zu Zeiten des pre-ES6-Codes eingeführt wurde, um logisch verwandte Entitäten zu gruppieren. Er hilft, große Projekte zu strukturieren, indem er Klassen, Funktionen, Schnittstellen und Typen innerhalb eines einzigen Namensraums zusammenfasst, um Namenskonflikte zu vermeiden und den Code lesbarer zu machen.
Geschichte: Vor den Standards von JavaScript ES6 verwendeten Entwickler IIFE, Objekte und Namensräume, um Modularität zu simulieren. TypeScript führte das Schlüsselwort namespace (früher internal module) zur Gruppierung von Code ein.
Problem: Moderne Module (ES6 Module) wurden zum Standard, und beide Ansätze (Namespace und Modul) existieren parallel, was Verwirrung bei der Architekturplanung hervorruft – wann sollte ein Namespace verwendet werden und wann ein Modul?
Lösung: Namespaces sind immer noch nützlich zum Zusammenfassen von Hilfsfunktionen und -typen in reinen TypeScript-Projekten (z.B. bei der Generierung einzelner JS-Dateien durch outFile). Zur Aufteilung von Code zwischen Dateien, insbesondere beim Arbeiten mit npm und modernen Bundlern, ist es sinnvoller, Module zu verwenden. Namespaces werden häufig in internen Bibliotheken, Typdeklarationen und Situationen eingesetzt, in denen eine Strukturierung innerhalb einer Datei oder im alten Code erforderlich ist.
Codebeispiel:
namespace MyMath { export function add(a: number, b: number) { return a + b; } } console.log(MyMath.add(2, 3)); // 5
Schlüsselfunktionen:
Wenn man Namespaces aus verschiedenen Dateien kombiniert, entstehen dann ein Namespace oder mehrere?
TypeScript führt Declaration Merging durch – bei übereinstimmenden Namen werden verschiedene Teile des Namensraums zu einem zusammengeführt, sofern sie korrekt eingebunden und im selben Sichtbereich sind.
// 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; } } // Nach der Kompilierung enthält MathUtil beide Methoden
Kann man import/require für Namespaces wie für Module verwenden?
Nein, für Namespaces gibt es keinen Standard-Export oder benannten Export, sie können nicht mit der Standard-ES6-Syntax importiert werden. Ein Namespace ist ein rein TypeScript-Konzept, das nicht in JavaScript-Module transpiliert wird.
Kann man Werte aus einem Namespace in eine andere Datei über import importieren?
Nein, um auf einen Namespace aus anderen Dateien zuzugreifen, ist die Verwendung von Referenzen (/// <reference path="..." />) oder die Kompilierung mit outFile erforderlich, ein Import über import ist nicht möglich.
In einem alten Projekt wurde die Logik auf Dutzende von Namespaces aufgeteilt, dieselben Namen traten in mehreren Dateien auf, was manchmal zu unerwarteten Zusammenführungen oder Konflikten führte. Der Übergang zu einer modularen Architektur erwies sich als sehr arbeitsintensiv.
Vorteile:
Nachteile:
In einer großen Bibliothek wurde die API über Namespace-Deklarationen in einer Datei index.d.ts deklariert, wodurch alle Typen und Schnittstellen ohne Implementierungscode vereinheitlicht wurden. Dies ermöglichte es, die Verbraucher der Bibliothek schnell zu typisieren und den Vertrag zwischen den Teams einfach zu aktualisieren.
Vorteile:
Nachteile: