Ich habe nicht verstanden, wie wir sie kategorisieren?
Namespaces werden verwendet, um Ihren Code zu organisieren / zu kapseln. Externe Module werden verwendet, um Ihren Code zu organisieren / zu kapseln UND Ihren Code zur Laufzeit zu lokalisieren. In der Praxis haben Sie zur Laufzeit zwei Möglichkeiten: 1) Kombinieren Sie den gesamten transpilierten Code in einer Datei oder 2) Verwenden Sie externe Module und verfügen Sie über mehrere Dateien. Sie benötigen einen anderen Mechanismus, um an diese Dateien zu gelangen.
Wann soll eine Klasse, ein Namespace oder ein Paket exportiert werden?
Um einen Typ oder Wert außerhalb der Datei sichtbar zu machen, in der er sich befindet, müssen Sie ihn exportieren, wenn er sich innerhalb eines Namespace befindet. Ob Sie es auf der obersten Ebene oder innerhalb eines Namespace exportieren, entscheidet, ob es sich jetzt in einem externen Modul befindet.
Wenn wir Paket / Namespace exportieren, werden alle darin enthaltenen Klassen exportiert oder müssen explizit exportiert werden
Klassen in einem Namespace müssen immer explizit exportiert werden, damit die Klasse zur Kompilierungszeit außerhalb der Datei angezeigt wird, in der sie definiert ist.
Wie kann jeder von ihnen importiert / benötigt werden?
Dies hängt davon ab, ob Sie externe Module verwenden. Ein externes Modul muss immer importiert werden, um es zu "verwenden". Das Importieren eines Namespace, der sich nicht in einem externen Modul befindet, stellt lediglich einen Alias für den Namespace bereit. Sie müssen dem Alias immer noch den Typ / was auch immer voranstellen (und aus diesem Grund möchten Sie Namespaces im Allgemeinen nicht mit externen Modulen verwenden. Dies bedeutet, dass Sie immer ein Präfix verwenden müssen, wenn Sie auf etwas verweisen, das vom externen Modul bereitgestellt wird.) Namespaces, die sich nicht in einem externen Modul befinden, können sich über Dateien erstrecken. Wenn Sie sich also im selben Namespace befinden, können Sie auf alles verweisen, was vom exportiert wird Namespace ohne Import.
Um das oben Genannte wirklich zu verstehen, benötigen Sie Hintergrundwissen. Bei Verweisen / Namespaces / externen Modulen ist es wichtig zu verstehen, was diese Konstrukte zur Kompilierungszeit und zur Laufzeit tun.
Referenzanweisungen werden zur Kompilierungszeit verwendet, um Typinformationen zu lokalisieren. Ihre Quelle enthält ein bestimmtes Symbol. Wie findet der TypeScript-Compiler die Definition für dieses Symbol? Die Referenzanweisung wurde größtenteils vom tsconfig.json-Mechanismus subsumiert. Mit tsconfig.json teilen Sie dem Compiler mit, wo sich alle Ihre Quellen befinden.
Namespaces können Typdefinitionen und / oder Implementierungen enthalten. Wenn ein Namespace nur Typinformationen enthält, hat er überhaupt keine Laufzeitmanifestation. Sie können dies überprüfen, indem Sie sich die JS-Ausgabe ansehen und eine leere JS-Datei suchen. Wenn ein Namespace Implementierungscode enthält, wird der Code in einen Abschluss eingeschlossen, der einer globalen Variablen mit demselben Namen wie der Namespace zugewiesen ist. Bei verschachtelten Namespaces gibt es eine globale Variable für den Stammnamenraum. Überprüfen Sie erneut die JS-Ausgabe. Namespaces sind historisch gesehen die Art und Weise, wie JS-clientseitige Bibliotheken versucht haben, das Problem mit Namenskollisionen zu vermeiden. Die Idee ist, Ihre gesamte Bibliothek in einen Abschluss zu packen und dann einen möglichst kleinen globalen Footprint bereitzustellen - nur eine globale Variable, die auf den Abschluss verweist. Nun, das Problem ist immer noch, dass Sie einen Namen im globalen Raum beansprucht haben. Was wäre, wenn Sie beispielsweise zwei Versionen einer Bibliothek wollten? Ein TypeScript-Namespace hat immer noch das Problem, wie die Quelle für den Namespace gefunden werden kann. Das heißt, Quellcode, der auf AB verweist, hat immer noch das Problem, dem Compiler mitzuteilen, wie AB zu finden ist - entweder mithilfe von Referenzanweisungen oder mithilfe von tsconfig.json. Oder indem Sie den Namespace in ein externes Modul einfügen und dann das externe Modul importieren.
Externe Module stammen von serverseitigem JS. Es besteht eine Eins-zu-Eins-Entsprechung zwischen einem externen Modul und einer Datei im Dateisystem. Sie können die Dateisystemverzeichnisstruktur verwenden, um externe Module in einer verschachtelten Struktur zu organisieren. Das Importieren eines externen Moduls führt im Allgemeinen immer zu einer Laufzeitabhängigkeit von diesem externen Modul (die Ausnahme ist, wenn Sie ein externes Modul importieren, aber dann keinen seiner Exporte an der Wertposition verwenden - das heißt, Sie importieren nur das externe Modul um an seine Typinformationen zu gelangen). Ein externes Modul befindet sich implizit in einem Abschluss, und dies ist der Schlüssel: Der Benutzer des Moduls kann den Abschluss jeder gewünschten lokalen Variablen zuweisen. TypeScript / ES6 fügt zusätzliche Syntax hinzu, um die Exporte der externen Module lokalen Namen zuzuordnen. Dies ist jedoch nur eine nette Sache. Auf der Serverseite Das Auffinden eines externen Moduls ist relativ einfach: Suchen Sie einfach die Datei, die das externe Modul darstellt, im lokalen Dateisystem. Wenn Sie externe Module auf der Clientseite in einem Browser verwenden möchten, wird dies komplexer, da es kein Äquivalent zu dem Dateisystem gibt, in dem das Modul zum Laden verfügbar ist. Auf der Clientseite müssen Sie nun eine Möglichkeit haben, alle diese Dateien in einem Formular zu bündeln, das im Browser remote verwendet werden kann. Hier können Modulbündler wie Webpack (Webpack bietet jedoch weit mehr als nur Module bündeln) und Browserify kommt ins Spiel. Modulbündler ermöglichen die Laufzeitauflösung Ihrer externen Module im Browser. In einem Browser wird es komplexer, da es kein Äquivalent zum Dateisystem gibt, in dem das Modul zum Laden verfügbar ist. Auf der Clientseite müssen Sie nun eine Möglichkeit haben, alle diese Dateien in einem Formular zu bündeln, das im Browser remote verwendet werden kann. Hier können Modulbündler wie Webpack (Webpack bietet jedoch weit mehr als nur Module bündeln) und Browserify kommt ins Spiel. Modulbündler ermöglichen die Laufzeitauflösung Ihrer externen Module im Browser. In einem Browser wird es komplexer, da es kein Äquivalent zum Dateisystem gibt, in dem das Modul zum Laden verfügbar ist. Auf der Clientseite müssen Sie nun eine Möglichkeit haben, alle diese Dateien in einem Formular zu bündeln, das im Browser remote verwendet werden kann. Hier können Modulbündler wie Webpack (Webpack bietet jedoch weit mehr als nur Module bündeln) und Browserify kommt ins Spiel. Modulbündler ermöglichen die Laufzeitauflösung Ihrer externen Module im Browser.
Reales Szenario: AngularJS. Stellen Sie sich vor, externe Module existieren nicht, verwenden Sie einen einzelnen Namespace, um die Verschmutzung des globalen Raums zu begrenzen (im folgenden Beispiel befindet sich nur eine einzige Variable im globalen Raum), exportieren Sie nur Schnittstellen und verwenden Sie AngularJS-Abhängigkeitsinjektion, um Implementierungen vorzunehmen zur Verwendung verfügbar. Fügen Sie alle Klassen in ein Verzeichnisstammverzeichnis ein, fügen Sie dem Stammverzeichnis eine tsconfig.json hinzu, installieren Sie anglejs-Typisierungen unter demselben Verzeichnisstammverzeichnis, damit tsconfig.json sie ebenfalls aufnimmt, und kombinieren Sie alle Ausgaben in einer JS-Datei. Dies funktioniert für die meisten Projekte einwandfrei, wenn die Wiederverwendung von Code kein großes Problem darstellt.
MyService.ts:
namespace MyApp {
// without an export the interface is not visible outside of MyService.ts
export interface MyService {
....
}
// class is not exported; AngularJS DI will wire up the implementation
class MyServiceImpl implements MyService {
}
angular.module("MyApp").service("myService", MyServiceImpl);
}
MyController.ts:
namespace MyApp {
class MyController {
// No import of MyService is needed as we are spanning
// one namespace with multiple files.
// MyService is only used at compile time for type checking.
// AngularJS DI is done on the name of the variable.
constructor(private myService: MyService) {
}
}
angular.module("MyApp").controller("myController", MyController);
}
Verwenden von IIFE, um eine Verschmutzung des globalen Laufzeitbereichs zu vermeiden. In diesem Beispiel werden überhaupt keine globalen Variablen erstellt. (Eine tsconfig.json wird angenommen.)
Foo.ts:
namespace Foo {
// without an export IFoo is not visible. No JS is generated here
// as we are only defining a type.
export interface IFoo {
x: string;
}
}
interface ITopLevel {
z: string;
}
(function(){
// export required above to make IFoo visible as we are not in the Foo namespace
class Foo1 implements Foo.IFoo {
x: string = "abc";
}
// do something with Foo1 like register it with a DI system
})();
Bar.ts:
// alias import; no external module created
import IFoo = Foo.IFoo;
(function() {
// Namespace Foo is always visible as it was defined at
// top level (outside of any other namespace).
class Bar1 implements Foo.IFoo {
x: string;
}
// equivalent to above
class Bar2 implements IFoo {
x: string;
}
// IToplevel is visible here for the same reason namespace Foo is visible
class MyToplevel implements ITopLevel {
z: string;
}
})();
Mit IIFE können Sie die Einführung von MyApp als globale Variable im ersten Beispiel eliminieren.
MyService.ts:
interface MyService {
....
}
(function() {
class MyServiceImpl implements MyService {
}
angular.module("MyApp").service("myService", MyServiceImpl);
})();
MyController.ts:
(function() {
class MyController {
constructor(private myService: MyService) {
}
}
angular.module("MyApp").controller("myController", MyController);
})();