GA am 8. Juli 2026  ·  Project Corsa

TypeScript 7
Der Umstiegs­guide

Compiler und Language Service wurden von TypeScript nach Go portiert. Das Ergebnis sind 8- bis 12-fach schnellere Builds — und eine Handvoll harter Brüche, die man kennen sollte, bevor man npm install tippt.

Vollständiger Build — Echtzeit, 10× beschleunigt
tsc  · TypeScript 60.00 s
tsc  · TypeScript 70.00 s
Messwerte aus Microsofts GA-Ankündigung (--checkers 4). Die Schätzung für dein Projekt verwendet den Faktor der gewählten Codebase.
01

Was tatsächlich passiert ist

TypeScript 7.0 ist kein Feature-Release. Es ist derselbe Compiler, noch einmal geschrieben — in Go statt in TypeScript.

Über ein Jahr lang hat das Team den bestehenden Compiler und Language Service Zeile für Zeile nach Go portiert. Der erklärte Anspruch war Treue statt Neuerfindung: Struktur und Logik der Originalcodebasis blieben erhalten, damit beide Compiler dieselben Ergebnisse liefern. Was sich ändert, ist ausschließlich das Fundament — nativer Maschinencode statt JavaScript, echte Threads mit gemeinsamem Speicher statt Single-Thread-Node.

Praktisch heißt das drei Dinge. Erstens: tsc ist eine native Binary, kein Node-Skript mehr. Zweitens: Der Language Service spricht jetzt LSP, läuft also in jedem modernen Editor und kann mehrere Anfragen parallel bedienen. Drittens — und das ist der teure Teil — es gibt in 7.0 keine stabile Programmier-API. Alles, was TypeScript bisher als Bibliothek eingebunden hat, läuft vorerst weiter gegen 6.0.

Namenshistorie

In den Vorschauversionen hieß die Binary tsgo und lag im Paket @typescript/native-preview. Seit GA heißt sie wieder tsc und liegt im normalen typescript-Paket. Ältere Blogposts und Stack-Overflow-Antworten reden noch von tsgo — gemeint ist dasselbe Programm.

02

Die Zahlen

Microsofts eigene Messungen auf öffentlichen Codebases, vollständiger Build, Standardeinstellung --checkers 4:

CodebaseTS 6TS 7FaktorSpeicher
vscode125,7 s10,6 s11,9×−18 %
sentry139,8 s15,7 s8,9×−6 %
bluesky24,3 s2,8 s8,7×−26 %
playwright12,8 s1,47 s8,7×−11 %
tldraw11,2 s1,46 s7,7×−15 %

Bemerkenswert ist die zweite Spalte von rechts: Der Speicherbedarf sinkt, obwohl parallel gearbeitet wird. Mit --checkers 8 steigt der Faktor auf der vscode-Codebase auf 16,7× (7,51 s), allerdings zulasten des Speichers.

Für den Alltag zählt aber weniger der Full Build als der Editor. Im vscode-Repository dauerte es früher rund 17,5 Sekunden vom Öffnen bis zum ersten angezeigten Fehler — jetzt unter 1,3 Sekunden. Microsoft berichtet außerdem von über 80 % weniger fehlgeschlagenen Language-Server-Kommandos und über 60 % weniger Server-Abstürzen gegenüber 6.0.

Einordnung

Alle Zahlen oben stammen vom Hersteller. Unabhängige Berichte aus den ersten Wochen nach GA lagen grob im selben Bereich, aber der ehrliche Satz lautet: Der Faktor auf deiner Codebase hängt von deren Form ab — viele kleine Dateien parallelisieren besser als wenige riesige mit tiefen Typabhängigkeiten.

03

Installation und Editor

Der Bezugsweg ist unspektakulär — genau das ist der Punkt:

Terminal
# Stabiles TypeScript 7
npm install -D typescript
npx tsc --version

# Nightlies der 7er-Linie
npm install -D typescript@next

# Einmal ohne Emit durchchecken
npx tsc --noEmit

Im Editor läuft alles über LSP. Für VS Code gibt es eine eigene Extension (TypeScriptTeam.native-preview), die sich nach der Installation automatisch als Standard setzt; über die Befehlspalette lässt sie sich mit „Disable TypeScript 7 Language Server" jederzeit wieder abschalten — ein Schalter, den man im Migrationsalltag öfter braucht, als man denkt. Visual Studio aktiviert TypeScript 7 abhängig vom Workspace von selbst, andere Editoren binden es als gewöhnlichen LSP-Server ein.

04

Die neuen Defaults

TypeScript 7.0 übernimmt die Standardwerte von 6.0. Wer von 5.x kommt, überspringt damit zwei Bruchkanten auf einmal.

Der offizielle Satz lautet: Code, der unter 6.0 mit stableTypeOrdering und ohne ignoreDeprecations sauber kompiliert, kompiliert unter 7.0 identisch. Der Umkehrschluss ist die eigentliche Arbeit — 6.0 zuerst, dann 7.0.

Optionaltneu ab 6.0 / 7.0
strictfalsetrue
modulecommonjsesnext
targetes5 / es3aktuelles ES (derzeit es2025)
noUncheckedSideEffectImportsfalsetrue
libReplacementtruefalse
stableTypeOrdering—true, nicht abschaltbar
rootDirabgeleitet./ (Config-Verzeichnis)
typesalle @types[] (leer)

Die zwei, die wirklich beißen

types ist jetzt leer. Bisher lud TypeScript stillschweigend jedes Paket unter node_modules/@types in den globalen Scope. In größeren Monorepos sind das schnell mehrere hundert Deklarationsdateien. Ab sofort lädt es keines mehr — bis du sie aufzählst. Das Symptom ist unmissverständlich: plötzlich kennt niemand mehr process, describe oder Bun.

tsconfig.json
{
  "compilerOptions": {
+   "types": ["node", "jest"]
//  ["*"] stellt das alte Verhalten wieder her – aber genau das kostete Zeit
  }
}

Microsoft berichtet, dass allein das explizite Setzen von types die Buildzeit vieler Projekte um 20 bis 50 Prozent verbessert hat. Der Default ist also kein Ärgernis, sondern das größte kostenlose Performance-Geschenk der Migration.

rootDir ist jetzt das Config-Verzeichnis. Früher wurde das gemeinsame Wurzelverzeichnis aus allen Eingabedateien abgeleitet. Jetzt ist es schlicht der Ordner, in dem die tsconfig.json liegt. Das Symptom: Deine Ausgabe landet in dist/src/index.js statt in dist/index.js.

tsconfig.json
{
  "compilerOptions": {
    "outDir": "./dist",
+   "rootDir": "./src"
  },
  "include": ["./src"]
}

stableTypeOrdering

Diese Option verdient eine eigene Erklärung, weil sie erklärt, warum die Parallelisierung überhaupt funktionieren kann. TypeScript vergab interne Typ-IDs bisher in der Reihenfolge, in der Typen dem Compiler begegneten — und sortierte Unions danach. Eine unbeteiligte const weiter oben in der Datei konnte den emittierten Union-Typ von 100 | 500 zu 500 | 100 drehen.

Bei parallelem Type-Checking wäre diese Reihenfolge nicht mehr deterministisch: Verschiedene Checker sehen verschiedene Reihenfolgen, und identische Dateien könnten unterschiedliche Deklarationsdateien oder sogar unterschiedliche Fehler produzieren. TypeScript 7 sortiert deshalb inhaltsbasiert und deterministisch. In 6.0 kann man dieses Verhalten mit --stableTypeOrdering vorab einschalten — kostet dort bis zu 25 % Checkzeit, ist aber während der Migration die ehrlichste Vergleichsbasis.

Wenn dabei Fehler auftauchen

Ein neuer Fehler unter stableTypeOrdering bedeutet fast immer: Die Inferenz hat vorher zufällig funktioniert, weil die Reihenfolge günstig war. Das Gegenmittel ist eine explizite Annotation — ein Typargument am Aufruf oder eine Typannotation an der Variablen, die hineingereicht wird.

05

Entfernt: die harten Fehler

Was in 6.0 eine Deprecation-Warnung war, ist in 7.0 ein Fehler ohne Ausweichflag. ignoreDeprecations hilft hier nicht mehr.

target: es5
Niedrigstes Ziel ist es2015. Wer wirklich ES5 ausliefern muss, schaltet einen externen Compiler nach.
downlevelIteration
Wirkte nur bei ES5-Emit und ist damit gegenstandslos. Ersatzlos streichen.
moduleResolution: node / node10
Bildete Node.js 10 ab. Ersatz: nodenext für Node-Ziele, bundler für Bundler und Bun.
moduleResolution: classic
Der Algorithmus von vor Node. Ersatz: bundler oder nodenext.
module: amd, umd, systemjs, none
Ersatz: esnext oder preserve, kombiniert mit einem Bundler. Die amd-module-Direktive wirkt nicht mehr.
baseUrl
War zugleich Präfix für paths und Suchwurzel für Modulauflösung — die zweite Rolle war meist unbeabsichtigt. Präfix in die paths-Einträge ziehen.
outFile
Bereits in 6.0 entfernt. Bundler machen das besser. Auf Rollup, esbuild, Vite oder Webpack umstellen.
esModuleInterop: false
allowSyntheticDefaultImports: false
Lassen sich nicht mehr abschalten. import * as express wird zu import express.
alwaysStrict: false
Aller Code gilt als strict. Bezeichner wie await, static, private oder public müssen umbenannt werden.
module Foo { }
Das module-Schlüsselwort für Namespaces ist ein Fehler — namespace Foo { } verwenden. declare module "x" bleibt unverändert gültig.
import … asserts { }
Die Import-Assertions wurden im Standard zu Import-Attributes. with { type: "json" } verwenden.
/// <reference no-default-lib />
Wird nicht mehr respektiert. Ersatz: --noLib oder --libReplacement.
tsc foo.ts neben tsconfig.json
Früher wurde die Config still ignoriert. Jetzt ist es ein Fehler — bewusst mit --ignoreConfig quittieren.
baseUrl auflösen — tsconfig.json
{
  "compilerOptions": {
-   "baseUrl": "./src",
    "paths": {
-     "@app/*": ["app/*"],
-     "@lib/*": ["lib/*"]
+     "@app/*": ["./src/app/*"],
+     "@lib/*": ["./src/lib/*"]
    }
  }
}

Falls baseUrl tatsächlich als Suchwurzel diente — selten, aber es kommt vor — lässt sich das mit einem Catch-all "*": ["./src/*"] nachbilden. Für die mechanischen Anteile dieser Umstellung gibt es das experimentelle Werkzeug ts5to6, das baseUrl und rootDir automatisch anpassen kann.

06

Fix-Generator

Kreuze an, was auf dein Projekt zutrifft. Unten entsteht die passende tsconfig.json plus die Punkte, die sich nicht durch Konfiguration lösen lassen.

Was trifft auf dein Projekt zu?
0 gewählt
{
  "compilerOptions": {
    // Nichts ausgewählt – die Defaults von 7.0 reichen.
  }
}
Noch keine Handarbeit nötig.

Der Generator deckt Konfiguration ab, nicht Semantik. Was danach an Typfehlern übrig bleibt, ist echte Arbeit an deinem Code — vor allem, wenn strict neu dazukommt.

07

Parallelisierung steuern

Parsing und Emit lassen sich sauber über Dateien verteilen. Type-Checking nicht: Fast jede Datei zieht Typinformationen aus ihren Abhängigkeiten und dem globalen Scope. TypeScript 7 löst das mit einer festen Anzahl von Checker-Workern, die jeweils ihre eigene Sicht auf das Programm haben, sich die Dateien bei gleichem Input immer identisch aufteilen — und deshalb reproduzierbar dieselben Ergebnisse liefern, auch wenn sie manche Arbeit doppelt machen.

Terminal
# Standard: 4 Checker
tsc

# Mehr Kerne, mehr Tempo, mehr Speicher
tsc --checkers 8

# CI-Runner mit wenig RAM: keine Doppelarbeit
tsc --checkers 1

# Monorepo: mehrere Projekte gleichzeitig bauen
tsc --build --checkers 4 --builders 4   # bis zu 16 Checker gleichzeitig!

# Alles seriell – zum Debuggen und Vergleichen
tsc --singleThreaded
FlagWirkungKosten
--checkers nType-Checker-Worker (Default 4)Speicher, Doppelarbeit
--builders nparallele Projekte unter --buildmultipliziert mit --checkers
--singleThreadedalles seriell, auch Parsing und Emitvolle Geschwindigkeit weg
Der eine Fallstrick

In seltenen Fällen kann eine unterschiedliche Anzahl Checker reihenfolgeabhängige Ergebnisse sichtbar machen. Deshalb: eine feste Zahl über alle Umgebungen hinweg festlegen — lokal, CI und Release-Build sollten denselben Wert verwenden. --builders ist davon nicht betroffen.

Watch-Modus

Der Watch-Modus wurde komplett neu gebaut. Go hat keine Dateiüberwachung in der Standardbibliothek, und die verfügbaren Bibliotheken überzeugten nicht — also portierte das Team den Watcher des Parcel-Bundlers von C++ nach Go, mit einigen Assembly-Shims, um keine C++-Toolchain in den Buildprozess zu holen. Wer tsc --watch auf einem großen Repository mit vollem node_modules laufen lässt, merkt den Unterschied vor allem am Leerlaufverbrauch.

08

Änderungen an Typsystem und JS-Support

Template-Literal-Typen respektieren Codepoints

Bisher folgte die Inferenz in Template-Literal-Typen der UTF-16-Indizierung von JavaScript und zerlegte Emoji in ihre Surrogatpaare. Das war formal konsistent, aber praktisch fast nie gewollt.

TypeScript
type HeadTail<S> = S extends `${infer Head}${infer Tail}` ? [Head, Tail] : never;

type R = HeadTail<"😀abc">;
// TS 7:  ["😀", "abc"]
// TS 6:  ["\ud83d", "\ude00abc"]

Das Verhalten entspricht jetzt dem, was for…of oder [...str] zur Laufzeit tun. Für die allermeisten Projekte ist das eine Korrektur. Wer allerdings auf Typebene absichtlich UTF-16-Einheiten gezählt hat — etwa in einem generischen Length<S>-Helfer — bekommt hier andere Ergebnisse.

JavaScript und JSDoc

Beim Portieren hat das Team die Sonderbehandlung von .js-Dateien aufgeräumt. Vieles davon war über Jahre gewachsen und an Closure-Konventionen orientiert; jetzt wird JavaScript weitgehend so analysiert wie TypeScript. Was das konkret bedeutet:

Werte als Typen
Nicht mehr erlaubt — typeof someValue schreiben.
@enum
Keine Sonderbehandlung mehr. Ersatz: ein @typedef auf (typeof MeinEnum)[keyof typeof MeinEnum].
Alleinstehendes ?
Kein gültiger Typ mehr — any verwenden.
@class
Macht aus einer Funktion keinen Konstruktor mehr. Echte class-Deklaration verwenden.
Postfix !
Nicht unterstützt — schlicht T schreiben.
@typedef-Platzierung
Der Name gehört in das Tag: /** @typedef {T} Name */, nicht daneben.
Closure-Funktionssyntax
function(string): void entfällt. Ersatz: (s: string) => void.
this-Aliasing, prototype-Zuweisung
Muster wie var self = this oder das Ersetzen des kompletten prototype werden nicht mehr besonders behandelt.

Diese Liste ist in Bewegung. Das Team pflegt die vollständigen Unterschiede zwischen 6.0 und 7.0 in der Datei CHANGES.md im typescript-go-Repository — die verlässlichste Quelle, wenn ein Fehler auftaucht, der in keinem Blogpost steht.

09

Das Ökosystem — hier liegt die eigentliche Arbeit

Der Compiler ist stabil. Was in den ersten Wochen nach GA Probleme machte, war alles andere.

Der Grund ist ein einziger: TypeScript 7.0 liefert keine stabile Programmier-API. Jedes Werkzeug, das TypeScript nicht als Kommandozeile aufruft, sondern als Bibliothek einbindet — Linter, Testrunner, Bundler-Loader, Template-Checker — greift ins Leere. Die neue API ist für 7.1 angekündigt.

tsc auf der Kommandozeile
Voll nutzbar. Type-Check, Watch, Project References, Build.
Editor / LSP
VS Code, Visual Studio, WebStorm und alles andere mit LSP-Unterstützung.
typescript-eslint
Braucht die Programmier-API. Ein am GA-Tag eingereichtes Support-Issue wurde als „not planned" geschlossen — die Lösung liegt bei 7.1, nicht bei typescript-eslint. Erzwungene Installation quittiert der Linter mit einem Absturz tief in typescript-estree.
ts-jest, ts-morph, ts-loader, Webpack-Loader
Dieselbe Ursache. Alles, was programmatisch typprüft oder transformiert, bleibt bis 7.1 auf der 6er-Linie.
Vue, Svelte, Astro, MDX
Template-Typprüfung läuft über Volar, das TypeScript einbettet. Bis 7.1 komplett auf 6.0.
Angular
Geteilter Betrieb möglich: TypeScript 7 auf der Kommandozeile für schnelle projektweite Fehler, TypeScript 6 im Editor für die Template-Prüfung.

Das Side-by-Side-Muster

Microsoft hat für genau diesen Übergang das Paket @typescript/typescript6 veröffentlicht. Es bringt eine Binary namens tsc6 mit und re-exportiert die vollständige 6.0-API. Weil Werkzeuge wie typescript-eslint per Peer-Dependency direkt aus typescript importieren, führt der Weg über npm-Aliase:

package.json
{
  "devDependencies": {
    // tsc  -> TypeScript 7 (schnell, für Check und Build)
    "@typescript/native": "npm:typescript@^7.0.2",

    // tsc6 -> TypeScript 6 (API-Oberfläche für Linter, Jest, Volar)
    "typescript": "npm:@typescript/typescript6@^6.0.2"
  }
}
package.json — scripts
{
  "scripts": {
    "typecheck":      "tsc --noEmit",          // 7.0, schnell
    "typecheck:legacy": "tsc6 --noEmit",         // 6.0, Referenz
    "build":          "tsc6 -p tsconfig.build.json",
    "lint":           "eslint ."              // nutzt weiter 6.0
  }
}
Empfehlung für die Übergangszeit

Zwei Compiler, zwei Aufgaben. TypeScript 7 ist der schnelle Prüfer — im Editor und als nicht-blockierender Schritt in CI. TypeScript 6 bleibt die Quelle der Wahrheit für Emit und für alles, was die API braucht. Sobald 7.1 mit stabiler API da ist, fällt die zweite Hälfte weg.

10

Migration in Phasen

Die Reihenfolge ist wichtiger als das Tempo. Wer direkt von 5.x auf 7.0 springt, bekommt die Brüche von zwei Major-Versionen gleichzeitig auf den Tisch und kann nicht mehr unterscheiden, welcher Fehler woher kommt.

Migrations-Checkliste
0 / 18
  • Phase 0 — Grundlage schaffen
  • Auf TypeScript 6.0 aktualisieren, noch mit "ignoreDeprecations": "6.0"
  • Baseline messen: tsc --noEmit mit Zeitmessung, Fehlerzahl notieren
  • Alle Deprecation-Warnungen einsammeln und als Tickets ablegen
  • Phase 1 — Konfiguration bereinigen
  • types explizit setzen — meist ["node"] plus Testrunner
  • rootDir explizit setzen, Ausgabepfade in dist/ prüfen
  • baseUrl entfernen, Präfixe in die paths-Einträge ziehen
  • moduleResolution auf nodenext oder bundler heben
  • target, module, outFile, downlevelIteration abräumen
  • ignoreDeprecations entfernen — ab hier muss 6.0 sauber sein
  • Phase 2 — strict und Reihenfolge
  • strict: true aktivieren, notfalls modulweise über Project References
  • --stableTypeOrdering einschalten und die neuen Fehler abarbeiten
  • Emittierte .d.ts zwischen 6.0 und 7.0 vergleichen
  • Phase 3 — 7.0 daneben stellen
  • TypeScript 7 per npm-Alias parallel installieren, 6.0 unangetastet lassen
  • Nicht-blockierenden CI-Job mit tsc --noEmit ergänzen
  • --checkers festlegen und über alle Umgebungen gleich halten
  • Team-Editoren auf den TS-7-Language-Server umstellen (außer bei Volar-Stacks)
  • Phase 4 — umschalten
  • CI-Job auf blockierend stellen, sobald die Fehlerlisten deckungsgleich sind
  • Emit auf 7.0 umstellen — nur wenn kein API-Werkzeug in der Build-Kette hängt
  • 7.1 im Blick behalten und das 6.0-Alias entfernen, sobald die API da ist

Der Haken wird nicht gespeichert — die Liste ist zum Durcharbeiten in einer Sitzung gedacht, nicht als Projektmanagement.

11

Was als Nächstes kommt

Mit 7.0 ist der Port abgeschlossen, und das Team kehrt zur normalen Arbeit zurück: neue Sprachfeatures, Ergonomie, weitere Performance — und die neue API. Die Kadenz soll wieder bei einem Release alle drei bis vier Monate liegen.

Die wichtigste Zahl für die Planung ist deshalb nicht 8× oder 12×, sondern 7.1. Bis dahin ist TypeScript 7 ein hervorragender Type-Checker und Editor-Motor mit einem Loch in der Werkzeugkette. Danach ist es einfach TypeScript.

Kurzfassung

Erst 6.0 sauber machen. Dann 7.0 daneben stellen, nicht darüber. Emit zuletzt umstellen. Und die types-Zeile nicht vergessen — sie ist die billigste Beschleunigung der ganzen Migration.