Ein umfassender Leitfaden zum „Modulsystem“ in TypeScript (mit Beispielen)
On Oktober 16, 2021 by adminModulstandard
EcmaScript hat standardisiert, wie wir Module in JavaScript importieren sollten und dieser Standard dreht sich um zwei Schlüsselwörter, import
und export
. Da das Modulsystem in JavaScript immer beliebter wird, gibt es jedes Jahr neue Änderungen an diesem Standard.
In diesem Tutorial werden wir uns die Semantik des Modulsystems in TypeScript ansehen (das größtenteils dem EcmaScript-Standard ähnelt) und wie import
und das export
-Schlüsselwort funktionieren.
Benannte Exporte
Das export
-Schlüsselwort macht einen Wert (Variable), der in einer Datei definiert ist, für den Import in andere Moduldateien verfügbar. Wenn ein Modul in eine andere Moduldatei mit dem Schlüsselwort import
importiert wird, kann die importierende Datei die Werte angeben, auf die sie aus dem importierten Modul zugreifen möchte.
// program.ts
import { A } from 'path/to/values';console.log( A ); // "Apple"
Im obigen Beispiel importieren wir values.ts
in die Datei program.ts
und extrahieren das exportierte Mitglied A
. Das bedeutet, dass values.ts
den Wert A
in irgendeiner Form exportieren muss. Es gibt mehrere Möglichkeiten, A
zu exportieren.
// values.ts
var A = "Apple"; // can also use `let` or `const`
class B {}
function C(){}
enum D{}export { A, B, C, D };
Sie können jeden zugänglichen TypeScript-Wert mit einem gültigen Bezeichner (Namen) exportieren. In diesem Beispiel exportieren wir eine Variable A
(könnte auch eine Konstante sein), eine Klasse B
und so weiter. Mit der Syntax export {}
können Sie so viele Werte exportieren, wie Sie wollen, und jeder kann sie mit der Syntax import { A, B }
importieren. Sie müssen nicht alle exportierten Werte importieren.
Es gibt eine weitere Möglichkeit, einen Wert dort zu exportieren, wo er deklariert wurde.
// values.ts
export const A = { name: "Apple" };
export class B {}
export function C(){}
export enum D{}
Im obigen Beispiel haben wir alle Werte dort exportiert, wo sie deklariert wurden. Sie brauchen den Wert auch nicht zu initialisieren, das können Sie später in der Datei tun. Dies ist ein viel angenehmerer Weg als der vorherige.
In beiden Fällen sind alle exportierten Elemente in derselben Datei zugänglich, wenn Sie sie verwenden müssen. Das Schlüsselwort export
für einen Wert ändert nicht sein Verhalten innerhalb der Moduldatei.
Standardexport
Bislang haben wir Werte exportiert, die nur importiert werden können, indem wir den Namen von Exportmitgliedern wie import { A } from 'path/to/values'
angeben, wobei A
hier ein Exportmitglied von values.ts
ist. Diese werden als benannte Exporte bezeichnet.
Sie können auch einen einzelnen Wert exportieren, der ohne Angabe eines Namens importiert werden kann. Dieser Wert sollte mit dem Schlüsselwort default
zusammen mit dem Schlüsselwort export
identifiziert werden.
// values.ts
var A = "Apple"; // can also use `let` or `const`
class A {}
function A(){}
enum A{}export default A;
Nur ein einzelner Wert darf als Standardexport exportiert werden, daher gibt es keinen export default {...}
-Ausdruck, mit dem Sie arbeiten können. Im Gegensatz zu benannten Exporten kann ein Wert nicht als Standard mit einer Variablen- (oder Konstanten-) Deklaration exportiert werden, mit Ausnahme einer function
– und class
-Deklaration.
// values.ts
export default var A = "Apple"; // ❌ invalid syntax
export default enum D{} // ❌ illegal: not a function or class
export default class B {} // ✅ legal
export default function C(){} // ✅ legal
Sie können jedoch einen Wert direkt als Standard-Export exportieren. Das bedeutet, dass jeder JavaScript-Ausdruck als Standardexportwert exportiert werden kann.
// values.ts
export default "Hello"; // string
export default {}; // object
export default () => undefined; // function
export default function(){}; // function
export default class{}; // class
Da der Standardexport keinen Exportnamen hat, können wir beim Importieren einen beliebigen Namen für ihn angeben. Sie können benannte Exporte und einen Standardexport in der gleichen Moduldatei haben. Ebenso können Sie den Standardexport und die benannten Exportwerte in einer einzigen import
-Deklaration importieren, wie unten gezeigt.
import Apple, { B, C } from 'path/to/values';
Im obigen Beispiel ist Apple
der Name, den wir verwendet haben, um den Standardexport aus values.ts
zu sammeln. Sie können den Ausdruck { B, C }
oder den Namen Apple
in der import
-Deklaration weglassen, wenn Sie ihn nicht verwenden wollen.
💡 Wie bei benannten Exporten ist es nicht zwingend erforderlich, den Standard-Exportwert zu importieren, wenn die
import
-Deklaration verwendet wird. Aber dieApple
muss vor den benannten Exporten in derimport
-Deklarations-Signatur stehen.
Sie können auch die as default
-Syntax in der export {}
-Signatur verwenden, um einen Wert als Standard zusammen mit anderen benannten Exporten zu exportieren. Dies wird Aliasing genannt und im nächsten Abschnitt erklärt.
// values.ts
var A = "Apple"; // can also use `let` or `const`
class B {}
function C(){}
enum D{}export { A as default, B, C, D };
💡 Der Grund, warum ich den
default
Export nicht verwende und empfehle, hat mit der Erfahrung der Entwickler zu tun. Wie wir gelernt haben, kann man in derimport
-Deklaration einen beliebigen Namen für den Standard-Export-Member eines Moduls angeben. Wenn dieser Wert in mehrere Dateien importiert wird, können Sie ihn mit einem beliebigen Namen referenzieren, und verschiedene Namen für dasselbe Export-Member desselben Moduls zu haben, ist ein schlechter DX.
Import und Export Alias
Im Fall des Standard-Exports können Sie den Wert mit einem beliebigen Namen in der import
-Deklaration referenzieren. Bei benannten Exporten ist dies jedoch nicht der Fall. Sie können jedoch das Schlüsselwort as
verwenden, um einen benannten Exportwert mit dem Namen Ihrer Wahl zu referenzieren.
// program.ts
import A, { B as Ball } from 'path/to/values';console.log( B ); // ❌ Error: Cannot find name 'B'.
console.log( Ball ); // ✅ legal
Im obigen Beispiel importieren wir B
aus values.ts
, aber es wurde in Ball
umbenannt. In der Datei program.ts
würden Sie daher Apple
anstelle von B
verwenden. Wenn Sie ein Exportmitglied mit einem Alias versehen, existiert der ursprüngliche Name nicht mehr im globalen Bereich, daher wird B
in der Datei program.ts
nicht mehr existieren.
💡 Sie können das Standard-Exportmitglied nicht mit einem Alias versehen, da Sie bereits einen beliebigen Namen Ihrer Wahl angeben können, aber Sie können
import { default as defaultValue, }
verwenden.
Sie können auch einen Wert beim Exportieren mit dem Schlüsselwort as
aliasieren.
// values.ts
var A = "Apple"; // can also use `let` or `const`
class B {}
function C(){}
enum D{}export { A as default, B, C as Cat, D };
Im obigen Beispiel haben wir die Variable A
als Standardexport und die Funktion C
als Cat
exportiert. Daher muss jeder, der diese Werte aus der Datei values.ts
importiert, die Standard-Import-Syntax für A
und Cat
für den Wert C
verwenden.
Alle benannten Exporte importieren
Sie können alle benannten Exporte aus einer Datei mit der Syntax * as
importieren.
// program.ts
import Apple, * as values from 'path/to/values';console.log( values.B );
console.log( values.C );
console.log( values.D );
Hier werden alle benannten Exporte aus values.ts
unter values
gespeichert, das ein Objekt ist, bei dem keys
der Name der Exportmitglieder und values
die exportierten Werte der Exportmitglieder sind.
Wiederexporte
Ein importierter Wert kann auf normale Weise wiederexportiert werden. Wenn man etwas importiert, hat man einen Verweis auf den Importwert, und man kann denselben Wert in der export
-Syntax verwenden. Daran ist nichts auszusetzen.
// lib.ts
import A, { B, C as Cat, D } from 'path/to/values';export { D as default, A, B, Cat as C, D };
Im obigen Beispiel haben Sie einige Werte aus values.ts
in lib.ts
importiert und nach Ihren Wünschen exportiert. Das ist ideal, wenn Sie diese Importe in lib.ts
verwenden und einige von ihnen exportieren möchten, wenn eine andere Datei sie benötigt, wenn sie aus lib.ts
importiert.
Es gibt jedoch auch die Anweisung export ... from
, mit der Werte aus einer Datei exportiert werden können, ohne dass sie zuerst importiert werden müssen. Dies ist ideal, wenn Sie einen einzigen Einstiegspunkt für alle Importe in Ihrem Modul haben möchten.
// lib.ts// re-exports
export { P as Paper, Q } from 'path/to/values-1';
export { N, O as Orange } from 'path/to/other/values-2';// default export
export default "hello";class B {}
function C(){}// named exports
export { B, C as Cat };
Im obigen Beispiel exportieren wir einige der Exportmitglieder von values-1.ts
und values-2.ts
aus der Datei lib.ts
(mit Ausnahme des Standard-Exports). Wir können auch Aliasing in der export ... from
-Syntax verwenden.
Die Re-Export-Syntax wirkt sich nicht auf die aktuelle Datei aus, daher können Sie Ihre regulären Exporte auch in der Datei haben, wie oben gezeigt. Im Gegensatz zum export
-Schlüsselwort erlaubt die export ... from
-Syntax keinen Zugriff auf re-exportierte Mitglieder. Daher können Sie nicht auf P
oder Orange
in der lib.ts
-Datei zugreifen.
// lib.ts
export { P as Paper, Q } from 'path/to/values-1';
export { N, O as Orange } from 'path/to/other/values-2';console.log( P ); // ❌ Error: Cannot find name 'P'.
console.log( Orange ); // ❌ Error: Cannot find name 'Orange'.
Sie können alle benannten Exporte aus einer Datei mit der export * from
-Syntax exportieren, wenn Sie die Möglichkeit haben, sie beim Exportieren mit export * as ... from
umzubenennen.
// lib.ts
export * from 'path/to/values-1';
export * as values2 from 'path/to/other/values-2';
Wenn im obigen Beispiel values-1.ts
P
und Q
exportiert, kann jeder P
und Q
aus lib.ts
importieren. Allerdings werden alle benannten Exporte von values-2.ts
als values2
benannter Export von lib.ts
wieder exportiert, daher müssen Sie sie mit der folgenden Syntax importieren:
// program.ts
import { P, Q, values2 } from 'path/to/lib';
Sie können nicht auf den Standardexport zugreifen, indem Sie die export ... from
-Syntax auf normale Weise verwenden. Aber Sie können den Standardexport mit dem Schlüsselwort default
exportieren.
// lib.ts
export { default } from 'path/to/values-1';
export { default as Apple } from 'path/to/values-2';
Im obigen Beispiel ist der Standardexport von lib.ts
der Standardexportwert von values-2.ts
. Der Standardexportwert von values-2
wird von lib.ts
als Apple
mit dem Namen export exportiert.
Importieren als Nebeneffekt
Können Sie sich vorstellen, eine Datei zu importieren, ohne die exportierten Mitglieder anzugeben?
import 'path/to/action';
Im obigen Beispiel importieren wir action.ts
, aber wir haben alle Mitglieder angegeben, die von action.ts
exportiert werden. Dies ist eine gültige Syntax, aber sie wird verwendet, um ein ganz anderes Ergebnis zu erzielen.
Wenn Sie eine Datei mit dem Schlüsselwort import
importieren, wird sie zuerst ausgeführt, und dann sind alle Exportmitglieder für den Import verfügbar. Im folgenden Beispiel würde also eine Datei, die PI
importiert, die 3.14
als floating-point
Nummer erhalten.
export const PI = parseFloat( "3.14" ); // 3.14
Wenn man der gleichen Logik folgt und durch den Import einer Datei einen Nebeneffekt erzeugen will, kann man das durchaus tun. Wenn es zum Beispiel eine Datei gibt, die einige globale Variablen initialisiert, können Sie diese importieren, ohne die exportierten Mitglieder dieser Datei anzugeben (sie könnte auch gar keine exportieren).
TypeScript-Compiler kann eine JavaScript-Bundle-Datei (.js
) erstellen, indem er zwei oder mehr .ts
-Dateien zusammen kompiliert. Dies geschieht normalerweise, indem man eine TypeScript-Eingangsdatei bereitstellt und dann ihren Abhängigkeitsbaum durchgeht.
Ein Abhängigkeitsbaum wird konstruiert, indem man alle import
Deklarationen (Abhängigkeiten) der Eingangsdatei betrachtet und den Abhängigkeiten dieser importierten Dateien folgt. Wenn Sie eine Datei einbinden wollen, deren Code zur Laufzeit einige Nebeneffekte erzeugen könnte, dann sollten Sie diese Datei importieren, ohne die exportierten Mitglieder in der import
-Syntax anzugeben. Dies kann in der Eingabedatei oder in einer beliebigen Datei innerhalb des Abhängigkeitsbaums geschehen.
Schreibe einen Kommentar