Wenn Sie jemals eine JavaScript-Applikation in einer Produktionsumgebung bereitgestellt haben, wissen Sie bereits, wie man eine TypeScript-Applikation ausführt. Nach der Kompilierung zu JavaScript sind beide nicht besonders verschieden. In diesem Kapitel geht es um die Erstellung von TypeScript-Applikationen und deren Vorbereitung für die Produktion. Dabei gibt es gar nicht so viele Besonderheiten. Dieses Kapitel ist in vier Abschnitte gegliedert:
Die Erstellung eines TypeScript-Projekts ist ganz einfach. In diesem Abschnitt decken wir die wichtigsten Punkte ab, die Sie verstehen müssen, um Ihr Projekt für eine beliebige Umgebung zu erstellen.
Ich empfehle Ihnen, für den Quellcode Ihres TypeScript-Projekts ein eigenes Verzeichnis namens src/ anzulegen und diesen in ein dist/-Verzeichnis zu kompilieren. Diese Ordnerstruktur wird per Konvention recht oft genutzt. Sie verteilt den Quellcode und den generierten Code auf zwei Ordner direkt unterhalb des Projektordners (my-app) auf. Das erleichtert Ihnen außerdem das Leben, wenn Sie mit externen Werkzeugen arbeiten müssen, und hilft zu kontrollieren, welche erzeugten Dateien (Artefakte) in die Versionierung aufgenommen werden sollen (siehe unten).
Versuchen Sie, sich nach Möglichkeit an diese Ordnerstruktur zu halten:
my-app/
├───dist/
│ ├──index.d.ts
│ ├──index.js
│ ├──services/
│ ├───foo.d.ts
│ ├───foo.js
│ ├───bar.d.ts
│ ├───bar.js
├──src/
│ ├──index.ts
│ └──services/
│ ├───foo.ts
│ └───bar.ts
Wenn Sie ein TypeScript-Programm zu JavaScript kompilieren, kann TSC verschiedene Artefakte für Sie erzeugen (siehe Tabelle 12-1).
Tabelle 12-1: Mögliche von TSC erzeugte Artefakte
Die erste Kategorie von Artefakten sollte Ihnen bekannt sein: JavaScript-Dateien. TSC kompiliert Ihren TypeScript zu JavaScript. Diesen können Sie dann auf einer JavaScript-Plattform wie NodeJS oder Chrome ausführen. Wenn Sie den Befehl tsc ihredatei.ts aufrufen, führt TSC ein Typechecking für ihredatei.ts durch und kompiliert sie zu JavaScript.
Die zweite Artefakt-Kategorie sind Sourcemaps. Dies sind spezielle Dateien, die für jeden Teil der erzeugten JavaScript-Datei eine Verbindung zu der entsprechenden Zeile und Spalte der TypeScript-Datei schaffen, aus der das JavaScript erzeugt wurde. Das hilft beim Debugging Ihres Codes (die Entwicklerwerkzeuge können beispielsweise den ursprünglichen TypeScript-Code anstelle des erzeugen JavaScript-Codes anzeigen). Kommt es bei der Ausführung von JavaScript zu Ausnahmen, lassen sich die Stacktraces zu den entsprechenden TypeScript-Quellen zurückverfolgen. (Durch die Verwendung von Sourcemaps können Werkzeuge, wie die in »Fehlerberichte« auf Seite 262 erwähnten, diese Rückverfolgung automatisch durchführen.)
Die dritte Form der Artefakte sind Typdeklarationen. Hiermit können andere TypeScript-Projekte Ihre erzeugten Typen ebenfalls verwenden.
Abschließend haben wir noch Deklarations-Maps. Sie werden verwendet, um die Kompilierungszeit Ihrer TypeScript-Projekte zu verkürzen. Mehr hierzu finden Sie unter »Projektreferenzen« auf Seite 260. Im übrigen Kapitel geht es darum, wie und warum diese Artefakte erzeugt werden.
Die Arbeit mit JavaScript hat gewisse Eigenarten. Durch den jährlichen Release-Zyklus entwickelt sich die Spezifikation sehr schnell. Als Programmierer können Sie aber nicht immer kontrollieren, welche JavaScript-Version die Zielplattform für Ihre Programme jeweils implementiert. Dazu kommt, dass JavaScript-Programme isomorph sind. Das heißt, Sie können sie entweder auf dem Server oder dem Client ausführen. Zum Beispiel:
Nicht jede JavaScript-Umgebung unterstützt jedes Feature von sich aus. Trotzdem sollten Sie versuchen, den Code in der neuesten Sprachversion zu schreiben. Hierfür gibt es zwei Wege:
TSC verfügt über eine eingebaute Unterstützung für die Transkompilierung Ihres Codes zu älteren JavaScript-Versionen, es stellt aber nicht automatisch Polyfills zur Verfügung. Noch einmal: TSC transkompiliert die meisten JavaScript-Merkmale für ältere Versionen, stellt aber keine Implementierungen für fehlende Features bereit.
In TSC gibt es drei Einstellungen, mit denen Sie die Zielumgebung festlegen können:
Die geplante Zielumgebung für Ihre Applikation legt fest, zu welcher JavaScript-Version Sie mit target transkompilieren und welche Einstellung für lib Sie verwenden sollten. Wenn Sie nicht sicher sind, ist es5 normalerweise eine sichere Standardeinstellung für beide Angaben. Die Einstellung für module hängt davon ab, ob Ihr Ziel NodeJS oder eine Browserumgebung ist und welchen Modul-Loader Sie im letzten Fall einsetzen.
Wenn Sie ungewöhnliche Plattformen unterstützen müssen, lohnt es sich, in Juriy Zaytsevs (auch als »Kangax« bekannt) Kompatibilitätstabellen (http://kangax.github.io/compat-table/es5/) nachzusehen, welche Merkmale die Zielplattformen jeweils unterstützen. |
Wir wollen uns zunächst etwas genauer mit target und lib beschäftigen. Auf module kommen wir in den Abschnitten »TypeScript auf dem Server ausführen« auf Seite 263 und »TypeScript im Browser ausführen« auf Seite 263 zu sprechen.
TSC besitzt einen eingebauten Transpiler (Transkompilierer), der die meisten JavaScript-Merkmale für ältere JS-Versionen konvertieren kann. Dadurch können Sie Ihren Code in der aktuellsten TypeScript-Version schreiben und ihn danach in die benötigte JavaScript-Version transkompilieren. Da TypeScript die aktuellsten JavaScript-Merkmale unterstützt (wie async/wait, die beim Schreiben dieses Buchs noch nicht von allen großen JavaScript-Plattformen unterstützt werden), werden Sie den eingebauten Transpiler häufig nutzen, um Ihren Code in etwas zu konvertieren, das NodeJS und Browser auch heute schon verstehen.
Sehen wir uns an, welche spezifischen JavaScript-Merkmale TSC für ältere JavaScript-Versionen transkompilieren kann und welche nicht (siehe Tabelle 12-2 und Tabelle 12-3).1
In der Vergangenheit wurden neue JavaScript-Revisionen alle paar Jahre mit aufsteigenden Versionsnummern (ES1, ES3, ES5, ES6) veröffentlicht. Ab 2015 verwendet JavaScript jedoch einen jährlichen Release-Zyklus, bei dem die Sprachversionen nach dem Jahr ihrer Veröffentlichung (ES2015, ES2016 etc.) benannt werden. Bestimmte JavaScript-Merkmale werden allerdings von TypeScript unterstützt, bevor sie Teil einer neuen JavaScript-Version sind. Wir bezeichnen diese Merkmale als »ESNext« (d.h. die nächste Revision). |
Tabelle 12-2: TSC transkompiliert
Version |
Merkmal |
ES2015 |
const, let, for..of-Schleifen, Array-/Objekt-Spreads (...), markierte (»tagged«) Template-Strings, Klassen, Generatoren, Pfeil-Funktionen, Standardparameter für Funktionen, Restparameter für Funktionen, Destrukturierung von Deklarationen/Zuweisungen/Parametern |
ES2016 |
Exponential-Operator (**) |
ES2017 |
async-Funktionen, await für Promises |
ES2018 |
async-Iteratoren |
ES2019 |
Optionale Parameter in catch-Klausel |
ESNext |
Numerische Trennzeichen (123_456) |
Tabelle 12-3: TSC nicht transkompiliert
Version |
Merkmal |
ES5 |
Getter/Setter für Objekte |
ES2015 |
Die Regex-Flags y und u |
ES2018 |
Das Regex-Flag s |
ESNext |
BigInt (123n) |
Um das Ziel einer Transkompilierung festzulegen, öffnen Sie Ihre tsconfig.json und geben dem target-Feld einen der folgenden Werte:
Um beispielsweise für ES5 zu kompilieren, schreiben Sie:
{
"compilerOptions": {
"target": "es5"
}
}
Wie gesagt, gibt es bei der Transkompilierung Ihres Codes für ältere JavaScript-Versionen einen Haken: Auch wenn die meisten Sprachmerkmale sicher transkompiliert werden können (let wird zu var, classs zu function etc.), müssen Sie immer noch ein Polyfill für den Fall bereitstellen, dass Ihre Zielplattform ein neueres Feature der Standardbibliothek nicht unterstützt. Hierzu gehören beispielsweise Hilfskonstrukte wie Promise und Reflect sowie Datenstrukturen wie Map, Set und Symbol. Ist Ihr Ziel eine der neuesten Chrome-, Firefox- oder Edge-Versionen, werden normalerweise keine Polyfills gebraucht. Wenn Sie auch ältere Browser – oder die meisten NodeJS-Umgebungen – unterstützen müssen, werden Sie diese Merkmale per Polyfill nachrüsten müssen.
Glücklicherweise müssen Sie die Polyfills nicht selbst schreiben. Stattdessen können Sie sie aus einer beliebten Polyfill-Bibliothek wie core-js (zu finden im NPM (https://www.npmjs.com/package/core-js)) installieren. Oder Sie fügen die Polyfills automatisch hinzu, indem Sie Ihren per Typechecking überprüften Code per @babel/polyfill (https://babeljs.io/docs/en/babel-polyfill) von Babel bearbeiten lassen.
Soll Ihre Applikation in einem Browser laufen, sollten Sie darauf achten, Ihren JavaScript-Code nicht unnötig aufzublasen. Das kann schnell passieren, wenn Sie Ihrem Paket alle möglichen Polyfills beilegen, ohne darauf zu achten, ob der jeweilige Browser diese wirklich braucht oder nicht. Sehr wahrscheinlich unterstützt Ihre Zielplattform zumindest ein paar der Merkmale, für die Sie Polyfills bereitstellen. Stattdessen sollten Sie einen Dienst wie Polyfill.io (https://polyfill.io/v2/docs/) verwenden, um nur die vom Browser wirklich gebrauchten Polyfills zu laden. |
Sobald Sie Ihren Code mit Polyfills versehen haben, können Sie TSC mitteilen, dass Ihre Umgebung die per Polyfill ergänzten Merkmale garantiert unterstützt. Hierfür gibt es das lib-Feld Ihrer tsconfig.json. Folgende Einstellung funktioniert, wenn Sie sämtliche ES2015-Merkmale sowie Array.prototype.includes aus ES2016 garantiert unterstützen:
{
"compilerOptions": {
"lib": ["es2015", "es2016.array.includes"]
}
}
Soll der Code im Browser ausgeführt werden, müssen Sie außerdem die Typdeklarationen für das DOM aktivieren, damit window, document und all die anderen APIs, die für die Verwendung von JavaScript im Browser gebraucht werden, richtig funktionieren:
{
"compilerOptions": {
"lib": ["es2015", "es2016.array.include", "dom"]
}
}
Eine komplette Liste der unterstützten Bibliotheken erhalten Sie per tsc --help.
Sourcemaps bieten die Möglichkeit, transkompilierten Code zu dem Quellcode zurückzuverfolgen, aus dem er erzeugt wurde. Die meisten Entwicklerwerkzeuge (z.B. die »Entwicklertools« in Chrome), Frameworks für die Erzeugung von Fehlerberichten und Fehlerprotokollierung und Build-Werkzeuge können mit Sourcemaps umgehen. Da ein typischer Build-Prozess oft Code produziert, der sich stark vom Ausgangscode unterscheidet, kann die Verwendung von Sourcemaps in Ihrer Build-Pipeline das Debugging des resultierenden JavaScript-Codes stark vereinfachen. (Ihre Pipeline könnte TypeScript beispielsweise zu ES5-JavaScript kompilieren, »toten« Code per Rollup (https://rollupjs.org/) entfernen, diesen mit Prepack (https://prepack.io) vorauswerten und ihn dann per Uglify (https://www.npmjs.com/package/uglify-js) minifizieren.)
Allgemein ist es eine gute Idee, Sourcemaps sowohl in der Entwicklung zu verwenden als auch in Produktionsumgebungen (sowohl im Browser als auch auf dem Server) zur Verfügung zu stellen. Dabei müssen Sie jedoch eines beachten: Wenn Sie versuchen, die Sicherheit durch unübersichtlichen Code (»security through obscurity«) zu erhöhen, sollten Sie Browsern in der Produktion keine Sourcemaps bereitstellen.
Je stärker Ihre Applikation wächst, desto länger braucht TSC, um das Typechecking und die Kompilierung Ihres Codes durchzuführen. Die benötigte Zeit wächst ungefähr linear mit der Größe Ihrer Codebasis. Wenn Sie lokal entwickeln, kann eine langsame inkrementelle Kompilierungszeit Ihre Entwicklung deutlich verlangsamen. Das kann mit der Zeit ziemlich schmerzhaft werden.
Um das Problem zu beheben, besitzt TypeScript ein Feature namens Projektreferenzen, das die Kompilierungszeiten, inklusive inkrementeller Kompilierungen, deutlich verringert. Für jedes Projekt, das länger als ein paar Hundert Zeilen ist, sind Projektreferenzen ein Muss.
Die Verwendung funktioniert so:
{
"compilerOptions": {
"composite": true,
"declaration": true,
"declarationMap": true,
"rootDir": "."
},
"include": [
"./**/*.ts"
],
"references": [
{
"path": "../myReferencedProject",
"prepend": true
}
],
}
Die wichtigen Punkte hierbei sind:
{
"files": [],
"references": [
{"path": "./myProject"},
{"path": "./mySecondProject"}
]
}
tsc --build # Oder kurz: tsc -b
Die Größe der tsconfig.json-Dateien per extends gering halten
Da vermutlich alle Subprojekte die gleichen Compiler-Optionen verwenden sollen, ist es sinnvoll, eine »Haupt«-tsconfig.json im Wurzelverzeichnis zu erstellen, die von den tsconfig.json-Dateien der Subprojekte erweitert werden kann:
{
"compilerOptions": {
"composite": true,
"declaration": true,
"declarationMap": true,
"lib": ["es2015", "es2016.array.include"],
"rootDir": ".",
"sourceMap": true,
"strict": true,
"target": "es5",
}
}
Danach können Sie die tsconfig.json-Dateien der Subprojekte mithilfe der extends-Option erweitern:
{
"extends": "../tsconfig.base",
"include": [
"./**/*.ts"
],
"references": [
{
"path": "../myReferencedProject",
"prepend": true
}
],
}
TypeScript warnt Sie vor Fehlern bei der Kompilierung. Sie müssen aber auch von Ausnahmen erfahren können, die zur Laufzeit beim Benutzer auftreten, damit Sie diese bereits bei der Kompilierung verhindern können (oder zumindest das Problem beheben, das den Laufzeitfehler ausgelöst hat). Monitoring-Werkzeuge wie Sentry (https://sentry.io) oder Bugsnag (https://bugsnag.com) können helfen, Laufzeitfehler zu melden und zusammenzufassen.
Um TypeScript in einer NodeJS-Umgebung auszuführen, kompilieren Sie Ihren Code einfach zu ES2015-JavaScript (oder ES5, falls eine ältere NodeJS-Version unterstützt werden soll). Das module-Flag in tsconfig.json benötigt hierbei den Wert commonjs:
{
"compilerOptions": {
"target": "es2015",
"module": "commonjs"
}
}
Dadurch werden die import- und export-Anweisungen aus ES2015 in Aufrufe von require und module.exports umgewandelt, damit Ihr Code ohne weiteres Bundling unter NodeJS läuft.
Falls Sie Sourcemaps verwenden (immer eine gute Idee!), müssen Sie diese dem NodeJS-Prozess übergeben. Laden Sie hierfür einfach das source-map-support-Package aus dem NPM und folgen Sie den Anweisungen zur Einrichtung. Die meisten Werkzeuge zur Prozessbeobachtung, Protokollierung und Berichterstattung wie PM2 (https://www.npmjs.com/package/pm2), Winston (https://www.npmjs.com/package/winston) und Sentry (https://sentry.io) unterstützen Sourcemaps bereits »von Haus aus«.
Die Kompilierung von TypeScript für die Ausführung im Browser ist etwas aufwendiger als beim Server.
Zu Beginn müssen Sie entscheiden, welches Modulsystem verwendet werden soll. Eine gute Faustregel ist, bei umd zu bleiben, um eine Bibliothek für andere zu veröffentlichen (z.B. auf NPM). Das maximiert die Kompatibilität mit den verschiedenen eingesetzten Module-Bundlern.
Wenn Sie Ihren Code nur selbst benutzen wollen, ohne ihn über NPM zu veröffentlichen, hängt das Kompilierungsformat davon ab, welchen Module-Bundler Sie verwenden. Überprüfen Sie hierfür die Dokumentation Ihres Bundlers. Webpack und Rollup funktionieren beispielsweise am besten mit ES2015-Modulen, während Browserify CommonJS-Module benötigt. Hier ein paar Richtlinien:
Danach konfigurieren Sie Ihre Build-Pipeline so, dass der gesamte TypeScript-Code zu einer JavaScript-Datei (dem »Bundle«) oder zu mehreren JavaScript-Dateien kompiliert wird. Für kleine Projekte kann TSC das über das outFile-Flag machen. Allerdings ist dieses Flag auf die Erzeugung von SystemJS- und AMD-Bundles beschränkt. Da TSC Build-Plug-ins und intelligente Codetrennung nicht so unterstützt wie ein spezielles Build-Werkzeug, z.B. Webpack, werden Sie sich früher oder später einen leistungsfähigerer Bundler wünschen.
Aus diesen Gründen sollten Sie für Frontend-Projekte von Anfang an ein mächtiges Build-Werkzeug verwenden. Es gibt TypeScript-Plug-ins für die verschiedensten Build-Werkzeuge Ihrer Wahl. Zum Beispiel:
Eine umfassende Diskussion der Optimierung Ihres JavaScript-Bundles würden den Rahmen dieses Buchs sprengen. Daher gebe ich Ihnen hier nur ein paar kurze Ratschläge, die übrigens nicht auf TypeScript beschränkt sind:
TypeScript-Code kann leicht so kompiliert werden, dass andere TypeScript- und JavaScript-Projekte ihn verwenden können. Bei der Kompilierung von TypeScript für die externe Benutzung sollte man allerdings ein paar Regeln beachten:
Beginnen Sie, indem Sie Ihr TypeScript mit tsc zu JavaScript kompilieren, und erzeugen Sie die dazu gehörigen Typdeklarationen. Konfigurieren Sie Ihre tsconfig.json so, dass die Kompatibilität mit beliebten JavaScript-Umgebungen und Build-Systemen möglichst groß ist (mehr dazu in »Das TypeScript-Projekt erstellen« auf Seite 253):
"compilerOptions": {
"declaration": true,
"module": "umd",
"sourceMaps": true,
"target": "es5"
}
}
Danach legen Sie in Ihrer .npmignore-Datei fest, dass Ihr TypeScript-Code nicht per NPM veröffentlicht werden soll. So vermeiden Sie, dass Ihr Package unnötig groß wird. In Ihrer .gitignore geben Sie an, dass die erzeugten Artefakte nicht Teil des Git-Repositorys sein sollen, um es nicht zu »verunreinigen«:
# .npmignore
*.ts # .ts-Dateien ignorieren...
!*.d.ts # ...aber .d.ts-Dateien erlauben
# .gitignore
*.d.ts # .d.ts-Dateien ignorieren
*.js # .js-Dateien ignorieren
Wenn Sie sich an das empfohlene Projektlayout (wie zu Beginn dieses Kapitels gezeigt) gehalten und ihre Quelldateien unter src/ bzw. die erzeugten Dateien unter dist/ abgelegt haben, sind Ihre .*ignore-Dateien sogar noch einfacher: |
|
|
# .npmignore src/ # Quelldateien ignorieren # .gitignore dist/ # Erzeugte Dateien ignorieren |
Zum Schluss fügen Sie der package.json Ihres Projekt ein "types"-Feld hinzu, um darauf hinzuweisen, dass Ihr Package Typdeklarationen enthält (das ist zwar nicht obligatorisch, aber ein hilfreicher Hinweis an TSC für alle TypeScript-Nutzer). Vor der Veröffentlichung geben Sie noch ein Build-Skript (im Feld "scripts") für Ihr Package an, um sicherzustellen, dass der JavaScript-Code, die Typdeklarationen und Sourcemaps immer aktuell und mit dem TypeScript-Code synchron sind, aus dem sie kompiliert wurden:
{
"name": "my-awesome-typescript-project",
"version": "1.0.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"prepublishOnly": "tsc -d"
}
}
Und das ist auch schon alles. Wenn Sie Ihr Package per npm publish veröffentlichen, wird NPM Ihr TypeScript automatisch in ein Format kompilieren, das sowohl TypeScript-Anwender (mit kompletter Typsicherheit) als auch JavaScript-Anwender (mit einer gewissen Typsicherheit, sofern ihr Codeeditor dies unterstützt) benutzen können.
TypeScript besitzt ein wenig bekanntes und benutztes und größtenteils veraltetes Merkmal namens Triple-Slash-Direktiven (»Drei Schrägstriche« – keine Fragezeichen, ///). Diese Direktiven sind speziell formatierte TypeScript-Kommentare, die als Anweisungen für TSC dienen.
Diese Direktiven gibt es in drei Geschmacksrichtungen, hier werden wir aber nur zwei behandeln: types, um den Import kompletter Module, die nur Typen enthalten, zu überspringen, und amd-module für die Benennung erzeugter AMD-Module. Eine komplette Referenz finden Sie unter Anhang E.
Je nachdem, was Sie aus einem Modul importieren, muss TypeScript bei der Kompilierung Ihres Codes zu JavaScript nicht unbedingt einen import- oder require-Aufruf erzeugen. Haben Sie beispielsweise eine import-Anweisung, deren Export nur in einer Typposition Ihres Moduls benutzt wird (d.h., es wird nur ein Typ aus dem Modul importiert), wird TypeScript keinen JavaScript-Code für diesen Import erzeugen. Der Import existiert quasi nur auf Typebene. Dieses Feature wird Import-Auslassung (»import elision«) genannt.
Die Ausnahme zu dieser Regel sind zweckentfremdete Importe: Wenn Sie ein komplettes Modul importieren (ohne einen bestimmten oder einen Wildcard-Export vorzunehmen), erzeugt dieser Import bei der Kompilierung Ihres TypeScript-Codes JavaScript-Code. Das kann etwa dann sinnvoll sein, wenn Sie sicherstellen wollen, dass ein ambienter Typ, der in einem Modul im Skriptmodus definiert wurde, Ihrem Programm zur Verfügung steht (wie wir das in »Prototypen sicher erweitern« auf Seite 156 getan haben). Zum Beispiel:
// global.ts
type MyGlobal = number
// app.ts
import './global'
Nach der Kompilierung von app.ts zu JavaScript mit dem Befehl tsc app.ts werden Sie feststellen, dass der Import von ./global nicht ausgelassen wurde:
// app.js
import './global'
Bei Importen wie diesem, wollen Sie zu Beginn wahrscheinlich sicherstellen, dass Ihre Importe diese Nebeneffekte wirklich benutzen müssen und dass es keine andere Möglichkeit gibt, in Ihrem Code expliziter zu formulieren, welchen Wert oder Typ Sie importieren (z.B. die Verwendung von import {MyType} from './global' – was TypeScript für Sie auslässt – anstelle von import './global'). Oder Sie können versuchen, Ihren ambienten Typ im types-, files- oder include-Feld Ihrer tsconfig.json unterzubringen und den Import auf diese Weise komplett zu vermeiden.
Manchmal funktioniert keiner dieser Wege, Sie wollen aber trotzdem ein komplettes Modul importieren. Anstatt einen JavaScript-import- oder require-Aufruf zu erzeugen, können Sie die Triple-Slash-Direktive types verwenden. Eine Triple-Slash-Direktive besteht aus drei Schrägstrichen ///, gefolgt von einem bestimmten XML-Tag, das jeweils bestimmte Attribute benötigt. Für die types-Direktive sieht das so aus:
/// <reference types="./global" />
/// <reference types="jasmine" />
Sie werden diese Direktive vermutlich nicht sehr oft benutzen. Und falls doch, sollten Sie überdenken, wie Typen in Ihrem Projekt verwendet werden. Vielleicht müssen Sie ambiente Typen gar nicht so oft einsetzen.
Bei der Kompilierung Ihres TypeScript-Codes in das AMD-Modulformat (erkennbar an {"module": "amd"} in Ihrer tsconfig.json) erzeugt TypeScript standardmäßig anonyme AMD-Module. Um die erzeugten Module mit Namen zu versehen, können Sie die Triple-Slash-Direktive amd-module verwenden.
Angenommen, Sie haben folgenden Code:
export let LogService = {
log() {
// ...
}
}
Dann erzeugt TSC bei der Kompilierung in ein amd-Modulformat folgenden JavaScript-Code:
define(['require', 'exports'], function(require, exports) {
exports.__esModule = true
exports.LogService = {
log() {
// ...
}
}
})
Wenn Ihnen das AMD-Modulformat bekannt ist, werden Sie bemerkt haben, dass es sich hier um ein anonymes AMD-Modul handelt. Um dem Modul einen Namen zu geben, verwenden Sie die Triple-Slash-Direktive amd-module in Ihrem Code wie hier:
/// <amd-module name="LogService" />
export let LogService = {
log() {
// ...
}
}
Wenn wir das mit TSC erneut ins AMD-Modulformat kompilieren, erhalten wir den folgenden JavaScript-Code:
/// <amd-module name='LogService' />
define('LogService', ['require', 'exports'], function(require, exports) {
exports.__esModule = true
exports.LogService = {
log() {
// ...
}
}
})
Wenn Sie Ihren Code zu AMD-Modulen kompilieren, können Sie die amd-module-Direktive einsetzen, um Ihren Code leichter zu verpacken und zu debuggen. (Oder Sie wechseln gleich zu einem moderneren Modulformat wie ES2015).
In diesem Kapitel haben wir alles behandelt, was Sie für das Erstellen und Ausführen Ihrer TypeScript-Applikation in einer Produktionsumgebung wissen müssen – im Browser oder auf dem Server. Wir haben darüber gesprochen, welche JavaScript-Version am besten für die Kompilierung geeignet ist, welche Bibliotheken in Ihrer Umgebung als verfügbar gekennzeichnet werden sollten (und wie Sie Polyfills verwenden können, falls sie nicht verfügbar sind). Wir haben gezeigt, wie Sie Sourcemaps erstellen und Ihrer Applikation beilegen können, um sie in der Produktion oder bei der lokalen Entwicklung leichter debuggen zu können. Danach haben wir erforscht, wie Sie Ihr TypeScript-Projekt modularisieren können, um die Kompilierungszeiten gering zu halten. Am Ende haben wir uns damit befasst, wie man eine TypeScript-Applikation auf dem Server und im Browser ausführt, wie Sie Ihren TypeScript-Code über den NPM veröffentlichen können, wie Import-Auslassungen (»elisions«) funktionieren und wie Benutzer von AMD Triple-Slash-Direktiven nutzen können, um ihre Module mit Namen zu versehen.