Programmiersprache TypeScript 4.7 verarbeitet ECMAScript-Module

Die Beta enthält neben der ursprünglich bereits für TypeScript 4.5 geplanten Anbindung an ESM eine erweiterte Kontrollflussanalyse für berechnete Properties.

In Pocket speichern vorlesen Druckansicht 26 Kommentare lesen
Schreibmaschine, Tastatur, Keyboard, Digitalisierung

(Bild: pixabay.com/Laszlo Zakarias, gemeinfrei)

Lesezeit: 5 Min.
Inhaltsverzeichnis

Microsoft hat turnusgemäß die erste Beta von TypeScript 4.7 veröffentlicht. Das Release des JavaScript-Superset bringt die ursprünglich bereits vor einem halben Jahr geplante Anbindung an ECMAScript Modules mit. Damit verbunden sind einige zusätzliche Einstellungen und Dateiendungen. Hinsichtlich der Programmiersprache selbst hat die aktuelle Version unter anderem Feinschliff für die Typinferenz über Kontrollflussanalyse und eine Ergänzung für Generics an Bord.

Node.js hat in den letzten Jahren ECMAScript Modules (ESM) neben dem traditionellen Modulsystem CommonJS (CJS) eingeführt und maßgeblich in Version 12 umgesetzt. Für TypeScript war die Integration von ESM ursprünglich bereits in Version 4.5 geplant, fehlte aber schließlich doch im Release. Als Grund nannte das Team vor allem Bedenken hinsichtlich der Usability, da der neue Modus mehr Verwirrung stiften als Nutzen bringen würde. In der Zwischenzeit hat es Feedback gesammelt und sieht die Programmiersprache nun als reif für die Umstellung an.

TypeScript 4.7 soll die Integration jetzt in leicht erweiterter Form umsetzen. Zum Aktivieren führt das Release unter den compilerOptions wie bereits für TypeScript 4.5 geplant die module-Einstellungen node12 und nodenext ein, um die Anbindung an ECMAScript Modules zu aktivieren.

Node kennt für die Datei package.json die Konfiguration "type". Dabei legt "module" das Zusammenspiel mit ESM fest, während "commonjs" für das ältere System steht. Erstere Einstellung erlaubt unter anderem import- und export-Anweisungen, und relative Importe benötigen anders als bei CJS die jeweilige Dateiendung wie ".js".

TypeScript untersucht für .ts-., .tsx-., .js-. oder .jsx-Dateien die zugehörige package.json, ob die Datei ein ES-Modul ist. Daraus ermittelt das System zum einen, wie es andere Module findet, die die Datei importiert. Beim Kompilieren von .ts-Dateien als ES-Modul fasst der Compiler zudem die import- und export-Anweisungen nicht an.

Für die benötigten Endungen in relativen Importen müssen Entwicklerinnen und Entwickler ihren Code anpassen, allerdings nehmen Auto-Importe und Pfadvervollständigung ihnen die Arbeit laut dem Blogbeitrag zur Beta von TypeScript 4.7 weitgehend ab.

Für die explizite Angabe des Modulsystems im Namen kennt Node.js die Endungen .mjs für ES-Module und .cjs für CommonJS Module. Analog dazu führt TypeScript .mts und .cts an, die es beim Übertragen in JavaScript-Dateien in .mjs und .cjs umwandelt. Für Deklarationen gibt es zusätzlich die Dateiendungen .d.mts und .d.cts.

ESM bringt einige grundlegende Änderungen beim Ausführen von JavaScript-Code mit sich und benötigt unter anderem definierte Moduleintrittspunkte. TypeScript sucht in Dateien nach import- und export-Anweisungen, um sie als Modul zu identifizieren. Dieses Vorgehen lässt sich in TypeScript 4.7 mit der neuen Konfiguration moduleDetection manuell überschreiben. "legacy" prüft weiterhin über import und export. "auto" ist die Standardeinstellung und testet zusätzlich unter anderem, ob das "type"-Feld in package.json auf "module" gesetzt ist. Unter "force" behandelt TypeScript jede Datei außer den Deklarationen als Modul.

Neben dem Zusammenspiel mit dem Modulsystem bringt TypeScript 4.7 einige Änderungen an der Sprache mit, die allerdings vor allem unter der Haube liegen. Unter anderem erweitert das Release die Kontrollflussanalyse, um den Typ berechneter Properties korrekt zu erkennen. Folgender Beispielcode aus dem TypeScript-Blog löst unter TypeScript 4.6 eine Fehlermeldung aus:

const key = Symbol();

const numberOrString = Math.random() < 0.5 ? 42 : "hello";

let obj = {
    [key]: numberOrString,
};

if (typeof obj[key] === "string") {
    let str = obj[key].toUpperCase();
}

Grund dafür ist, dass TypeScript für die Typinferenz nur die Deklaration von numberOrString nutzt, womit es wahlweise eine Zahl oder eine Zeichenkette sein kann. TypeScript 4.7 erkennt nun, dass aufgrund des strikten Gleichheitsoperators === der Typ von obj[key] innerhalb des Blocks string sein muss.

Nennenswert ist zudem eine Ergänzung für Generics, die eine direkte Zuweisung für einen bestimmten Typen erlaubt. Als Beispiel führt der Blogbeitrag folgendes Interface an:

interface Box<T> {
    value: T;
}

function makeBox<T>(value: T) {
    return { value };
}

Mit einer neuen Syntax lässt sich sowohl aus dem Konstruktor als auch aus dem Funktionsaufruf eine spezielle Variante anlegen, die lediglich beispielsweise string-Objekte akzeptiert:

const makeStringBox = makeBox<string>;

// TypeScript akzeptiert keine andere Zuweisung als string
// Folgende Zeile l�st daher einen Fehler aus:
makeStringBox(42);

Die Syntax lässt sich auch für Collections wie Array, Map und Set verwenden:

const ErrorMap = Map<string, Error>;
const errorMap = new ErrorMap();

Weitere Neuerungen in TypeScript 4.7 wie die erweiterte Funktionsinferenz für Objekte und Methoden lassen sich dem TypeScript-Blog entnehmen. Die Betaphase ist wie üblich auf gut sechs Wochen ausgelegt, und das endgültige Release soll laut Roadmap am 24. Mai erscheinen. Die ausführliche Diskussion zur Integration des Modulsystems ECMAScript Modules findet sich im zugehörigen Pull Request.

Siehe auch:

(rme)