Start / Seminare / Modern TypeScript 7
Modul
Migration auf TypeScript 7
10 Kapitel in diesem Modul-Video · Laufzeit
Transkript
Der gesprochene Text dieses Moduls zum Mitlesen, Überfliegen und Durchsuchen. Ein Klick auf einen Zeitstempel springt an die Stelle im Video.
Migration auf TypeScript 7
0:00 Willkommen zum dritten Tag. Hier läuft alles zusammen, was wir bisher gebaut haben: die Voreinstellungen aus Modul 1, die Typordnung aus Modul 3, die Modulauflösung aus Modul 7 und die Werkzeuglage aus Modul 8. Denn jetzt geht es um die praktische Frage, die die meisten von Ihnen ins Seminar geführt hat: Wie bringe ich ein bestehendes Projekt auf TypeScript 7?
0:21 Die gute Nachricht vorweg: Es gibt einen belegten Weg mit einer vorgegebenen Reihenfolge. Die weniger gute: Der Compilerwechsel selbst ist nicht die Arbeit. Die Arbeit liegt davor.
Migration auf TypeScript 7
0:33 Der Leitsatz für diesen Tag lautet: Sechs meldet als Warnung, was sieben als Fehler abweist. Darin steckt der ganze Plan. Version 6.0 ist Ihre Arbeitsvorbereitung — sie sagt Ihnen, was zu tun ist, ohne Sie zu blockieren. Wer diese Vorbereitung ernst nimmt, für den ist der eigentliche Wechsel ein Handgriff. Wer sie überspringt, bekommt beide Umstellungen gleichzeitig um die Ohren und weiß bei jedem Fehler nicht, welche der beiden ihn verursacht hat.
1:00 Fangen wir mit der Bestandsaufnahme an.
Inventur vor der Migration
1:03 Vor jeder Umstellung steht eine Bestandsaufnahme. Und ich beginne mit der Aussage, die die häufigste Fehleinschätzung im Vorfeld korrigiert: Der Aufwand hängt an der Liste, nicht an der Codegröße. Ein kleines Projekt mit exotischen Werkzeugen ist aufwendiger als ein großes mit gewöhnlichen. Vier Fragen bilden die Bestandsaufnahme. Welche Version läuft heute? Welche Einstellungen weichen vom Standard ab? Welche Abhängigkeiten bringen eigene Typen mit?
1:30 Und welche Werkzeuge greifen programmatisch auf den Compiler zu? Aus diesen vier Antworten entsteht eine Liste, und diese Liste bestimmt den Aufwand — nicht die Größe der Codebasis. Das ist eine sehr praktische Erkenntnis für die Planung: Sie können den Aufwand seriös schätzen, bevor Sie eine Zeile angefasst haben. Sie müssen nur die richtigen Dinge zählen.
1:52 Fünf Schritte, und Schritt drei entscheidet über den Termin, wie die Fußzeile sagt. Zuerst sammeln Sie die heutige Version und alle Konfigurationsdateien — samt der Vererbungsketten, die man leicht übersieht. Dann notieren Sie jede Abweichung vom Standard und suchen zu jeder den Grund; oft findet sich keiner mehr, und das ist bereits ein Ergebnis.
2:12 Drittens listen Sie die Werkzeuge auf, die den Compiler als Abhängigkeit führen. Viertens prüfen Sie eingebettete Sprachen. Und fünftens machen Sie daraus einen Plan — aus der Liste, nicht aus dem Bauchgefühl. Der erste Punkt ist die Fehleinschätzung, über die wir gerade gesprochen haben: nach Codezeilen schätzen statt nach Konfiguration und Werkzeugen.
2:33 Der zweite ist ein handfestes Erkenntnisproblem: Vererbungsketten in der Konfiguration übersehen und deshalb gar nicht wissen, welche Einstellungen tatsächlich gelten. Lassen Sie sich die aufgelöste Konfiguration ausgeben, statt die Dateien zu lesen. Und der dritte ist ein Reihenfolgefehler mit teuren Folgen: die Prüfung der Werkzeuge ans Ende stellen, wo sie nichts mehr ändern kann — außer den bereits zugesagten Termin.
Die Reihenfolge steht in der Ankündigung
2:57 Jetzt kommt der wichtigste Abschnitt dieses Moduls, und er beruht auf einem Satz, der fast überall verkürzt zitiert wird. Die Reihenfolge ist keine Empfehlung, die wir uns ausgedacht haben. Sie ist die Bedingung der Zusage — und der entscheidende Teil steht in einem Klammerzusatz. Die Ankündigung sagt Verhaltensgleichheit zu — aber ausdrücklich unter Bedingungen.
3:19 Wörtlich: Code, der unter 6.0 sauber übersetzt, und zwar mit eingeschalteter stabiler Typordnung und ohne den Schalter, der veraltete Optionen durchgehen lässt, übersetzt unter 7.0 identisch. Lesen Sie diesen Satz zweimal, denn genau die Klammer ist das Rezept. Wer die Bedingungen überspringt, hat die Zusage nicht — dann gilt kein Versprechen, und Abweichungen sind kein Fehler des Compilers, sondern eine unerfüllte Voraussetzung.
3:45 Fünf Schritte mit jeweils einem Grund, und der letzte ist der erfreulichste: Der Wechsel auf 7.0 ist der kleinste Schritt der ganzen Migration. Davor liegt die Arbeit. Auf 6.0 gehen, weil es als Warnung meldet, was später hart abgewiesen wird. Den Schalter für veraltete Optionen entfernen, weil 7.0 ihn gar nicht mehr kennt.
4:06 Die stabile Typordnung einschalten, die das Verhalten von 7.0 vorab nachbildet. Und dann sauber übersetzen — erst dann gilt die Zusage. Die Fußzeile nennt den Preis der Typordnung: bis zu 25 Prozent mehr Prüfzeit, vorübergehend. Nach dem Wechsel fliegt sie wieder raus. Der letzte Punkt ist der, den ich am häufigsten sehe: die Zusage zitieren und den Klammerzusatz weglassen.
4:30 Dann hört das Management „gleiches Verhalten garantiert" und Sie haben eine Erwartung erzeugt, die an Bedingungen hängt, die niemand kennt. Der erste Punkt ist die bequeme Selbsttäuschung: den Schalter gesetzt lassen und die Arbeit für erledigt halten. Und der zweite ist der Sprung von 5.x direkt auf 7.0 — damit bündeln Sie zwei Umstellungen zu einer und verlieren die Diagnosefähigkeit, die der Zwischenschritt Ihnen schenkt.
Die neuen Defaults aus TypeScript 6
4:54 Jetzt sehen wir uns an, was Version 6.0 tatsächlich umgestellt hat. Und die Überschrift beschreibt es genau: Was vorher stillschweigend galt, steht jetzt da — oder ist ersatzlos weg. Das ist die eigentliche Arbeit der Migration. Sieben Zeilen, und die interessantesten sind die mittleren. Die strenge Prüfung ist jetzt an — das bringt in Altbeständen die meisten neuen Meldungen.
5:18 Das Modulformat und die Zielversion sind modern. Die eingebundenen Typpakete sind leer statt „alles Gefundene" — dazu gleich mehr, das ist die folgenreichste Einzeländerung. Das Quellverzeichnis wird nicht mehr abgeleitet. Die Interoperabilität zwischen den Modulwelten ist an und lässt sich nicht mehr abschalten. Und der Compiler prüft jetzt Importe, die nur wegen ihrer Nebenwirkung dastehen.
5:42 Vier Punkte, die zusammen erklären, warum wir hier so viel Zeit investieren. Der Compilerwechsel selbst ändert am Code nichts — er übersetzt dasselbe, schneller. Die Voreinstellungen dagegen ändern, was der Compiler überhaupt beanstandet, und das ist eine ganz andere Kategorie von Änderung. Die strenge Prüfung allein bringt in Altbeständen die meisten neuen Meldungen.
6:03 Und die beiden Einstellungen zu Typpaketen und Quellverzeichnis bringen die meisten neuen Konfigurationsfragen. Wer diese Arbeit hinter sich hat, für den ist der Rest ein Paketwechsel. Der zweite Punkt ist der wichtigste Rat für Ihr Vorgehen: nicht alle Meldungen auf einmal beheben wollen, sondern in Stufen. Ein Altbestand liefert bei eingeschalteter Strenge schnell vierstellige Fehlerzahlen, und das lähmt. Gehen Sie modulweise oder regelweise vor.
6:30 Der erste Punkt ist ein alter Bekannter: die Voreinstellungen ausschreiben und die Datei damit unlesbar machen. Und der dritte ist schlicht eine Sackgasse: Die Interoperabilität zwischen den Modulwelten lässt sich nicht mehr abschalten. Wer darauf gebaut hat, muss den Code ändern.
types und rootDir ausdrücklich setzen
6:47 Zwei Einstellungen, die früher geraten wurden und jetzt hingeschrieben werden müssen. Die erste davon ist die folgenreichste Einzeländerung in Version 6.0 — und ihre Fehlermeldung wirkt zunächst rätselhaft, weil plötzlich Selbstverständliches unbekannt ist. Die erste Einstellung bestimmt, welche Typpakete global eingebunden werden. Früher waren es alle gefundenen — was immer zufällig im Verzeichnis lag, war Teil Ihres Projekts.
7:12 Jetzt keines ohne Nennung. Die zweite bestimmt die Wurzel Ihrer Quelldateien und wird nicht mehr aus ihnen abgeleitet. Beides ist unbequem beim Umstellen und danach ein Gewinn — und ich meine das ernst: Zufall ist eine schlechte Grundlage für Reproduzierbarkeit, auch wenn er bequem war. Sieben Zeilen, und jede ist eine Entscheidung. Die Node-Typen ausdrücklich genannt, das Quellverzeichnis, das Ausgabeverzeichnis.
7:37 Die Fußzeile nennt die beiden Symptome, an denen Sie das Fehlen erkennen: Ohne die Typangabe sind die Node-Globals unbekannt — und die Meldung, dass ein bekanntes Objekt nicht existiert, verwirrt erst einmal jeden. Ohne das Quellverzeichnis landet die Ausgabe in einer unerwartet verschachtelten Struktur, und dann stimmen alle Pfade in der Veröffentlichung nicht mehr.
7:58 Zwei Zeilen, zwei sehr häufige Migrationsstunden. Vier Gründe, und der zweite ist der überzeugendste: Ein zufällig installiertes Typpaket verändert die Prüfung nicht mehr. Früher konnte eine fremde Abhängigkeit, die ein Typpaket mitzog, das Verhalten Ihres Compilers ändern — ohne dass jemand etwas an Ihrem Projekt getan hätte.
8:19 Dazu kommt: Der Umfang eines Projekts dehnt sich nicht mehr unbemerkt aus. Die Ausgabestruktur ist ablesbar statt abgeleitet. Und ganz praktisch: weniger Prüfaufwand für den Compiler, also kürzere Läufe. Unbequemlichkeit mit vier Gegenwerten — das ist ein guter Tausch.
Veraltete Moduleinstellungen ablösen
8:36 Jetzt zu den Optionen, die ersatzlos entfallen sind — und es sind ganze Familien. Für die meisten Projekte ist das eine Formalität. Für einige ist eine davon ein echtes Thema, nämlich dann, wenn eine sehr alte Laufzeit bedient werden muss. Fünf Zeilen. Die alte Zielversion ist weg, mindestens die Generation von 2015 ist jetzt der Boden — was mit einer wirklich alten Laufzeit passiert, klären wir gleich.
9:02 Die zugehörige Hilfsoption entfällt mit ihr, sie funktionierte ohnehin nur dort. Das Zusammenfassen der Ausgabe in eine Datei ist weg, und die Anmerkung sagt trocken, warum: Bündeln war nie Compilerarbeit. Die alten Modulformate sind Geschichte. Und bei den Import-Zusätzen hat sich das Schlüsselwort geändert — eine rein mechanische Umstellung, aber eine, die man finden muss.
9:26 Für alle, die noch einen alten Browser oder ein altes Terminal bedienen müssen — und das kommt öfter vor, als man denkt. Der Compiler zielt auf mindestens die Generation von 2015 und geht nicht mehr rückwärts. Wer älter ausliefern muss, schaltet einen Übersetzungsschritt dahinter. Und das ist keine Notlösung: Diese Aufgabe wandert damit zum Bundler, wo sie ohnehin besser aufgehoben ist, weil er die Zielumgebung kennt und die Hilfsfunktionen mitbringt.
9:52 Der letzte Punkt ist trotzdem der wichtigste: Prüfen Sie im Zweifel, ob die alte Laufzeit überhaupt noch bedient werden muss. Oft ist die Antwort nein. Der erste Punkt spart Ihnen eine erfolglose Suche: Nein, die alte Zielversion lässt sich nicht mit irgendeiner Option zurückholen. Sie ist weg, und der Weg führt über einen nachgeschalteten Schritt.
10:12 Der zweite ist eine schlechte Idee mit gutem Motiv: das Zusammenfassen der Ausgabe durch handgeschriebene Verkettung ersetzen. Nehmen Sie einen Bundler. Und der dritte ist eine begriffliche Klarstellung, die zu Modul 6 gehört: Import-Zusätze sind kein Sprachfeature, das eine Prüfung ersetzt — sie sagen der Laufzeit, um was für eine Datei es sich handelt, mehr nicht.
Modulauflösung ohne baseUrl
10:34 Der Punkt aus Modul 7, jetzt in der Migrationsperspektive. Es gibt zwei Ersatzwege für den entfallenen Basispfad, und sie sind nicht gleichwertig — das ist die Kernaussage. Die Umstellung selbst ist maschinell machbar, die Entscheidung dahinter nicht. Die alten Auflösungsstrategien sind entfallen, es bleiben zwei: die Node-Auflösung und die Bundler-Auflösung. Der Basispfad ist ebenfalls weg.
10:59 Als Ersatz haben Sie zwei Möglichkeiten, und der Unterschied ist entscheidend. Die eine sind Pfadabbildungen relativ zur Konfigurationsdatei — eine reine Compiler-Fiktion, die zur Laufzeit nicht existiert. Die andere sind die Kurzpfade in der Projektdatei, die Node selbst auflöst und die deshalb auch zur Laufzeit gelten. Wenn Sie die Wahl haben, nehmen Sie die zweite.
11:21 Sie ist die einzige, die wirklich existiert. Für den mechanischen Teil gibt es ein Werkzeug, das genau diese beiden Umstellungen erledigt: den Basispfad entfernen und das Quellverzeichnis setzen. Die Fußzeile nennt zwei Dinge, die Sie wissen sollten. Erstens arbeitet es über Monorepos, Projektreferenzen und Vererbungsketten hinweg — also genau dort, wo Handarbeit fehleranfällig wäre.
11:45 Zweitens ist es in der Quelle ausdrücklich als experimentell gekennzeichnet. Das heißt: Lassen Sie es laufen, aber lesen Sie den Änderungssatz. Ein Werkzeug, das Konfiguration umschreibt, verdient einen prüfenden Blick. Alle drei Punkte kreisen um dieselbe Verwechslung: Automatisierung mit Entscheidung zu verwechseln. Das Werkzeug laufen lassen und die Frage überspringen, ob die Pfadabbildungen überhaupt bleiben sollen.
12:10 Die Abbildungen behalten, ohne Bundler oder Loader — und dann kommt der Fehler erst im Betrieb, weil beim Übersetzen alles stimmt. Und schließlich: erwarten, dass ein Werkzeug die Architekturentscheidung mitliefert. Das tut keines. Es kann Ihnen die Tipparbeit abnehmen, nicht die Frage, wie Ihre Module zueinander stehen sollen.
Zwei benannte Verhaltensunterschiede
12:30 Jetzt zu den einzigen beiden Abweichungen, die ausdrücklich benannt sind. Wenige — und genau deshalb sollte man gezielt nach ihnen suchen. Denn beide sind still: Sie brechen nichts sichtbar, sondern verändern Ergebnisse, die niemand prüft. Erstens die Typordnung: TypeScript 7 sortiert Unions inhaltsbasiert statt nach der Reihenfolge, in der sie angetroffen wurden.
12:53 Der Grund ist technisch zwingend und einleuchtend — die parallele Prüfung macht eine Antreffreihenfolge schlicht unmöglich, weil mehrere Dinge gleichzeitig passieren. Zweitens Unicode: Zeichen jenseits der Grundebene werden in zusammengesetzten Zeichenketten-Typen nicht mehr in Halbzeichen zerlegt. Das betrifft in erster Linie Emojis und Sonderschriften — selten, aber wenn, dann still.
13:16 Vier Zeilen, drei davon zur Typordnung, weil sie an drei verschiedenen Stellen sichtbar wird. In Fehlermeldungen und Tooltips — dort brechen festgehaltene Testergebnisse. In generierten Deklarationen — dort entstehen Änderungssätze ohne fachlichen Grund, was beim Prüfen nervt. Und in seltenen Grenzfällen kann ein Fehler erscheinen oder verschwinden.
13:36 Die Fußzeile ordnet das richtig ein, und ich unterstreiche das: Die Reihenfolge einer Union war nie zugesichert. Wer sich darauf verlassen hat, hat auf ein Implementierungsdetail gebaut — das ist kein Vorwurf, aber auch kein Fehler des Compilers. Vier konkrete Handgriffe für Ihre Migration. Lassen Sie zuerst die festgehaltenen Testergebnisse über Fehlermeldungen durchlaufen — dort schlägt es sofort zu.
14:01 Vergleichen Sie die generierten Deklarationen vor und nach dem Wechsel. Suchen Sie Typkonstruktionen, die Zeichenketten auf Typebene zerlegen — das sind meist wenige und sie sind auffindbar. Und der vierte ist der gründlichste: Lassen Sie beide Compiler dieselbe Codebasis prüfen und vergleichen Sie die Diagnosen. Wie das geht, sehen wir gleich — es ist offiziell vorgesehen.
Parallelbetrieb und Vergleich
14:23 Damit sind wir beim sichersten Werkzeug der ganzen Migration. Beide Compilerversionen laufen im selben Projekt nebeneinander. Und das Wichtige daran: Das ist offiziell vorgesehen und in der Ankündigung beschrieben — kein Trick, keine Improvisation. Beide Fassungen lassen sich im selben Projekt betreiben. Das ist der sicherste Weg, eine Migration abzunehmen: dieselbe Codebasis von beiden prüfen lassen und die Diagnosen vergleichen, statt in einem Sprung umzustellen und zu hoffen.
14:52 Damit verwandeln Sie eine Behauptung in einen Nachweis. Und das ist mehr als Sorgfalt — es ist das Argument, das Sie brauchen, wenn Sie im Unternehmen erklären sollen, warum die Umstellung sicher ist. Ein Vergleich zweier Diagnoselisten überzeugt, ein „hat bei mir funktioniert" nicht. Zwei Einträge, zwei Rollen, und die Zuordnung ist entscheidend. Der neue Compiler steht unter einem eigenen Namen und stellt den Befehl bereit — er prüft.
15:18 Der gewohnte Name zeigt per Alias auf das Kompatibilitätspaket, und dorthin greifen die Werkzeuge, wenn sie den Compiler importieren. Sie bekommen also die erwartete Schnittstelle, obwohl der eigentliche Prüflauf schon mit der neuen Fassung läuft. Das ist eine elegante Lösung für eine unangenehme Übergangszeit — und sie erlaubt Ihnen, jetzt anzufangen, statt auf 7.1 zu warten.
15:41 Vier Möglichkeiten, und die zweite ist die, die ich Ihnen besonders ans Herz lege: Buildzeiten auf der eigenen Maschine messen, statt fremde Zahlen zu übernehmen. Damit beantworten Sie die Frage aus Modul 1 und Modul 5 für Ihr Projekt — nicht für das Editor-Projekt von Microsoft. Dazu kommen: Diagnosen beider Fassungen vergleichen, Werkzeuge weiterlaufen lassen, die noch auf die neue Schnittstelle warten, und schließlich die Migration abnehmen, statt sie zu behaupten.
16:07 Der Unterschied zwischen abnehmen und behaupten ist genau die Diagnoseliste.
Die fehlende Compiler-API
16:12 Und damit zum Rückverweis auf Modul 8, hier aber ausschließlich mit Blick auf die Planung. Die Kernaussage steht in der Tagline und ist unbequem: Nicht der Code entscheidet über den Termin, sondern die Werkzeuge. TypeScript 7.0 liefert keine programmatische Compiler-Schnittstelle mit; sie ist für 7.1 vorgesehen. Alles, was den Syntaxbaum liest oder Typinformation programmatisch abfragt, kann deshalb noch nicht aufsetzen — typbezogene Lint-Regeln ebenso wie Werkzeuge für eingebettete Sprachen.
16:41 Das ist die Einschränkung, die wir seit Modul 1 mitschleppen, und hier zeigt sie ihre volle Wirkung auf die Planung. Es ist keine Frage von Aufwand oder Können. Es ist eine Frage des Wartens — und Warten plant man anders als Arbeit. Vier Konsequenzen, und die dritte definiert, wann Sie eigentlich fertig sind. Die Werkzeugliste bestimmt den Termin, nicht der Zustand des Codes.
17:04 Der Parallelbetrieb überbrückt die Lücke, ist aber kein Dauerzustand. Und dann: Die Migration ist erst abgenommen, wenn der Kompatibilitäts-Alias verschwunden ist — solange er dasteht, sind Sie mittendrin, nicht fertig. Und der vierte Punkt ist eine Bitte zur Kommunikation: Ein Termin für 7.1 ist nicht zugesagt. Vorgesehen ist nicht datiert, und dieser Unterschied kostet Sie sonst Ihre Glaubwürdigkeit.
17:30 Der erste Punkt ist der teuerste Fehler dieses Moduls: einen Migrationstermin zusagen, bevor die Werkzeuge geprüft sind. Prüfen Sie zuerst, sagen Sie danach zu — die Reihenfolge kostet Sie eine Stunde und rettet Ihnen einen Termin. Der zweite ist der Reflex, den wir schon kennen: die Abhängigkeitsprüfung erzwingen. Die fehlende Schnittstelle entsteht dadurch nicht.
17:52 Und der dritte ist eine Frage der Nachhaltigkeit: den Parallelbetrieb einrichten und nie wieder nach ihm sehen. Setzen Sie sich eine Erinnerung, wenn 7.1 erscheint.
Übung — ein Projekt migrieren
18:03 Jetzt machen Sie es selbst — in Schritten, mit Vergleich, mit Nachweis. Diese drei Wörter sind das Programm der Übung. Und im vorbereiteten Projekt warten vier Altlasten, die genau die Themen dieses Moduls treffen. Das Lernziel: eine Migration in nachvollziehbaren Schritten durchführen und ihr Ergebnis nachweisen, statt es zu behaupten.
18:23 Erfolgreich sind Sie unter drei Bedingungen: Beide Compilerfassungen liefern dasselbe Prüfergebnis, jeder Schritt hat einen eigenen Commit, und die Inventur ist abgearbeitet. Die einzelnen Commits sind kein Formalismus — sie sind das, was eine Migration zurückrollbar macht. Wer früh fertig ist, misst die Prüfzeit beider Fassungen auf derselben Maschine und vergleicht mit den Zahlen aus Modul 1 und 5. Das ist eine sehr aufschlussreiche Übung.
18:50 Fünf Schritte, in genau der Reihenfolge, die wir hergeleitet haben: Inventur zuerst, und darin die Werkzeuge zuerst. Dann den Schalter für veraltete Optionen entfernen und die Meldungen in Stufen abarbeiten. Die stabile Typordnung einschalten und sauber übersetzen — jetzt gilt die Zusage. Parallelbetrieb einrichten, beide Diagnosen vergleichen. Und das Ergebnis nachweisen. Ein Hinweis zum Snapshot-Test über eine Union: Er bricht, und das ist Absicht.
19:17 Die richtige Antwort ist nicht, die Ordnung zurückzudrehen — sondern zu erkennen, dass der Test auf einer nie zugesicherten Eigenschaft beruhte. Vier Sätze zum Mitnehmen. Die Verhaltensgleichheit gilt unter Bedingungen — und die stehen im Klammerzusatz, den fast alle weglassen. Schließen Sie erst 6.0 sauber ab, dann ist der Compilerwechsel der kleinste Schritt der ganzen Migration.
19:41 Basispfad und Quellverzeichnis lassen sich maschinell umstellen, die Entscheidung dahinter nicht. Und den Termin bestimmen die Werkzeuge, nicht der Zustand Ihres Codes. Im nächsten Modul geht es um die Zahl, wegen der viele überhaupt migrieren wollen — und darum, wie man sie für das eigene Projekt seriös ermittelt.
Lieber mit Trainer? Dieses Modul ist Teil unserer Team-Schulungen — mit Übungen, Ihrem eigenen Code und Fragen, die ein Video nicht beantwortet. Mehr erfahren →