Startseite / Artikel / TypeScript 7.0 wechselt den Compiler auf Go für native Geschwindigkeit

TypeScript 7.0 wechselt den Compiler auf Go für native Geschwindigkeit

TypeScript 7.0 überträgt tsc auf Go mit parallelen Überprüfern, neuen Standardwerten für tsconfig, Unicode-Template-Literals, strengeren JS-Analysen sowie einer vorübergehenden Lücke in der programmatischen API.

1086 Wörter

Etwa vierzehn Jahre lang konnte der TypeScript-Compiler sich selbst kompilieren. tsc war TypeScript, das in JavaScript kompiliert wurde und unter Node lief. Als die Repositorien auf Millionen von Zeilen anwuchsen, wurde dieses selbsthostete Design zu einem Engpass.

TypeScript 7.0 ändert die Hostsprache. Der Compiler sowie der Sprachdienst wechselten von TypeScript zu Go. Microsoft bezeichnet diese Übertragung als Portierung statt Neuimplementierung: Die Struktur der Typüberprüfung entspricht noch der von 6.0, doch die Ausführung erfolgt in Form von natives Code mit paralleler Verarbeitung über gemeinsam genutzte Speicher. Veröffentlichte Vergleiche zeigen in der Regel eine Geschwindigkeitssteigerung von etwa 10× im Vergleich zu TypeScript 6.0.

Eine häufig zitierte Arbeitslast macht diesen Wechsel konkret sichtbar: Die Überprüfung des VS Code-Trees – mit etwa 1,5 Millionen Zeilen TypeScript – dauerte von rund 77,8 Sekunden auf etwa 7,5 Sekunden ab.

Für frühere Berichterstattungen wurde der Codename Project Corsa verwendet (wobei der herkömmliche JavaScript-Tree den Spitznamen Strada erhielt); diese Version ist die Umsetzung dieser Bemühungen.

Warum Go – und warum eine Portierung?

In der Öffentlichkeit wurde oft Rust als mögliche Alternative genannt. Go wurde gewählt, weil es mit der Struktur des bestehenden Compilers übereinstimmte: komplexe Graphen, Garbage Collection sowie zyklische Strukturen, die schwierig von Grund auf neu erstellt werden könnten. Diese Übereinstimmung machte eine Zeile-für-Zeile-Portierung möglich.

Die Struktur der Portierung ist wichtiger als die Sprachmarke. Durch Beibehaltung der Architektur blieben auch die Regeln erhalten. Projekte, die bereits unter 6.0 mit stableTypeOrdering aktiviert und ohne ignoreDeprecations Typüberprüfungen durchführen, sollten unter 7.0 dieselben Ergebnisse erhalten – ein schnelleres Engine-System, kein anderes Typsystem.

Zuerst fanden die Produktions-Testläufe statt. Über ein Jahr lang arbeitete der Port mit großen Strukturen an Orten wie Bloomberg, Figma, Google, Slack, Notion und Vercel, bevor dieses Meilenstein erreicht wurde.

Echter Parallelismus

Bislang begrenzte ein einzelner Node-Thread die Durchsatzleistung. Native Worker beseitigen diese Beschränkung. Version 7 verteilt die Aufgaben parse, check und emit sowie fügt Flags hinzu:

  • --checkers legt die Anzahl der parallelen Typüberprüfungswerker fest
  • --builders parallelisiert die Kompilierung von Projektreferenzen sowie Stapelstrukturen in Monorepos zusammen mit --checkers
  • --singleThreaded bündelt alles auf einen Kern zusammen, um bei der Fehlerbehebung sowie zur Messung von Basistiming-Daten zu helfen

Die Aufgaben parse/emit pro Datei skalen mit der Größe und Modularität des Repositoriums; kleine Ein-Datei-Anwendungen profitieren weniger davon.

Auch der Überwachungsmodus wurde neu gestaltet. Das Abfragen verbrauchte viel CPU bei großen node_modules-Strukturen; die Einbeziehung von Parcels Überwachungsfunktion in Go verringert diesen Aufwand und reagiert schneller auf Änderungen.

Konfigurationsänderungen, die Teams herausfordern

TypeScript 6.0 diente als Übergang: Neue Standardwerte und veraltete Funktionen wurden als Warnungen angezeigt. 7.0 macht sie zu schwerwiegenden Fehlern. Teams, die bereits TypeScript 6.0 durchlaufen haben, haben den größten Teil der Arbeit erledigt. Ein direkter Sprung von 5.x auf 7.0 erfordert Zeit zur Anpassung von tsconfig.json.

Bemerkenswerte Änderungen der Standardeinstellungen:

  • strict ist standardmäßig aktiv, sofern nicht überschrieben
  • module wird auf esnext gesetzt, während target die neueste stabile ECMAScript-Version vor esnext auswählt
  • noUncheckedSideEffectImports ist standardmäßig aktiv
  • libReplacement ist standardmäßig deaktiviert
  • stableTypeOrdering bleibt aktiviert.
  • rootDir beginnt bei ./.
  • types startet als leere Liste.
  • In den Dokumentationen werden rootDir und types als die ersten Probleme bezeichnet, auf die Teams stoßen – und als diejenigen mit den einfachsten Lösungen.

    Falls tsconfig.json über einem src-Ordner liegt, geben Sie rootDir explizit an, damit die Ausgabe weiterhin vertraut aussieht:

    {
      "compilerOptions": {
        "rootDir": "./src"
      },
      "include": ["./src"]
    }
    

    Weil types nicht mehr automatisch alles unter node_modules/@types importiert, listen Sie auf, was Sie benötigen:

    {
      "compilerOptions": {
        "types": ["node", "jest"]
      }
    }
    

    Optionen, die zuvor nur gewarnt haben, führen jetzt zu Fehlern (sie erledigen nichts Nützliches mehr):

    • Löschen Sie target: es5 und downlevelIteration.
  • Ersetzen Sie die veralteten moduleResolution-Werte (node, node10, classic) durch nodenext oder bundler
  • Verwerfen Sie module-Modi wie amd, umd, systemjs und none zugunsten von esnext oder preserve
  • Entfernen Sie baseUrl und geben Sie die paths relativ zum Projektverzeichnis an
  • Achten Sie darauf, dass esModuleInterop / allowSyntheticDefaultImports nicht auf false gesetzt werden
  • Betrachten Sie alwaysStrict als dauerhaft aktiviert
  • Falls moduleResolution nach Jahren ohne Überprüfung immer noch auf den alten Wert node gesetzt ist, dient diese Datei als Migrationscheckliste.

    Unicode in Template-Literal-Typen

    Template-Literal-Typen beziehen sich nun auf Unicode-Codepunkte statt auf UTF-16-Codeeinheiten:

    type HeadTail<S> = S extends `${infer Head}${infer Tail}` ? [Head, Tail] : never;
    
    type Result = HeadTail<"😀abc">;
    // In 7.0:      ["😀", "abc"]
    // Previously:  ["\ud83d", "\ude00abc"]
    

    Ältere Compiler konnten ein Surrogatpaar eines Emojis in zwei Teile aufteilen. Das spiegelte die Indizierung in JavaScript wider und entsprach selten der Absicht des Autors. Die Iteration folgt nun den Codepunkten, genauso wie for...of und [...str]. Hilfsfunktionen, die absichtlich UTF-16-Einheiten zählten, werden nicht mehr funktionieren; alle anderen erhalten das erwartete Verhalten.

    Strengeere Analyse von JavaScript

    .js-Prüfungen tolerierten früher mehr JSDoc- und Closure-Era-Ideale. Version 7 bringt diese Richtung stärker in Einklang mit den .ts-Regeln:

    • Orte, die Typen benötigen, lehnen reine Werte ab – es wird typeof someValue bevorzugt
    • @enum / @class erhalten keine besondere Behandlung mehr; man muss eine echte Klasse deklarieren oder @typedef verwenden
    • Ein reines ? wird nicht als Typ akzeptiert – es wird any bevorzugt
  • Aufgehängte !-Assertionen werden nicht unterstützt – schreiben Sie explizit T.
  • Die alten function(string): void-Formen werden durch (s: string) => void ersetzt.
  • Das Defizit der programmatischen API

    In Version 7.0 fehlt weiterhin eine stabile programmatische API. Bibliotheken, die den Compiler integrieren – wie ESLints TypeScript-Integration, ts-morph, selbst entwickelte Transformer sowie Editor-Hilfsmittel für Vue, Svelte, Astro, MDX oder Angular-Templates – können daher noch nicht vollständig umsteigen. Microsoft betrachtet dieses Defizit als vorübergehend und verspricht die Fertigstellung der API für Version 7.1 und spätere Releases.

    Währenddessen kann man Version 7.0 verwenden, wenn keine Language-Server-Plugins erforderlich sind. Angular-Teams können beispielsweise tsc aus Version 7.0 nutzen, um schnelle CLI-Prüfungen im gesamten Projekt durchzuführen, während sie weiterhin Version 6.0 im Editor verwenden. Ein Kompatibilitätspaket namens @typescript/typescript6 stellt ein tsc6-Binärprogramm bereit und exportiert die 6.0-API erneut, sodass beide Versionen nebeneinander existieren können:

    {
      "devDependencies": {
        "typescript": "npm:@typescript/typescript6@^6.0.0"
      }
    }
    

    Sollten Sie upgraden?

    Da bereits TypeScript 6.0 verfügbar ist, ist der Migrationsaufwand gering und die Vorteile groß: Man passt nur einige Einstellungen in tsconfig an und erhält schnellere CI-Prüfungen sowie ein schnelleres Starten des Editors. Bei älteren Versionen gibt es tatsächlich Kompatibilitätsprobleme, doch fast alle wurden bereits angekündigt.

    Installieren Sie den Release Candidate noch heute:

    npm install -D typescript@rc
    

    Für Editor spricht heute ein VS Code-Add-on die LSP-Sprache, und die native Integration in VS Code erweitert sich stetig. Visual Studio erkennt Version 7.0 bereits im geöffneten Arbeitsbereich, ohne dass ein separater Installationsschritt erforderlich ist.

    Die Betreuer geben an, dass die Funktionsveröffentlichungen wieder im gewohnten mehrmonatigen Rhythmus stattfinden, und es wird erwartet, dass Version 7.1 die Lücke in der Embedding-API schließt.

    Letztes Ergebnis: die vertrauten TypeScript-Regeln, die als natives Code ausführt werden.