Die Codebasis, die ständig brach
Wir hatten ein Problem. Unser Hauptkundenprojekt — eine React SPA mit rund 50.000 Zeilen JavaScript — wurde zunehmend fragil. Jeder Sprint brachte Regressionen. Ein umbenannter Prop hier, eine geänderte API-Antwort dort, und plötzlich waren drei Seiten kaputt.
Das Team verbrachte mehr Zeit mit Debugging als mit Entwicklung. Etwas musste sich ändern.
Warum TypeScript? (Und warum wir gezögert haben)
Ich gebe zu: Anfangs war ich skeptisch. TypeScript fühlte sich nach Overhead an. Mehr Dateien, mehr Syntax, mehr Tooling. Unser kleines Team konnte es sich nicht leisten, langsamer zu werden.
Aber nach dem dritten Sprint in Folge, in dem wir einen Hotfix für einen typbezogenen Bug lieferten, wurde der Preis des Nicht-Migrierens deutlich. Wir sparten keine Zeit, indem wir TypeScript vermieden — wir verschwendeten sie auf die schlimmste Art: für vermeidbare Bugs.
Unsere Migrationsstrategie: Kein Big Bang
Wir haben einmal eine komplette Neufassung versucht. Bei einem anderen Projekt. Es scheiterte. Drei Wochen Arbeit weggeworfen.
Diesmal gingen wir inkrementell vor:
Phase 1 — Infrastruktur (Woche 1)
tsconfig.json mit strict: false und allowJs: true hinzugefügt. Den Einstiegspunkt umbenannt. Das war's. Die App lief noch. Keine Features kaputt. Teamvertrauen: intakt.
Phase 2 — Gemeinsame Typen (Woche 2-3)
Ein /types-Verzeichnis erstellt. Angefangen mit API-Response-Typen — das Ziel mit dem höchsten Wert und dem geringsten Risiko.
Phase 3 — Komponente für Komponente (laufend) Jedes Mal, wenn jemand eine Datei anfasste, konvertierte er sie. Keine dedizierten "Migrations-Sprints." Es passierte organisch als Teil der normalen Arbeit.
Die Überraschungen (gut und schlecht)
Was besser lief als erwartet
Onboarding-Geschwindigkeit verdoppelt. Neue Entwickler hörten auf zu fragen "Was macht dieser Prop?" Sie konnten über jede Variable hovern und den Typ sehen.
Refactoring wurde angstfrei. Vor TypeScript bedeutete das Umbenennen eines Props, die gesamte Codebasis zu durchsuchen und zu beten, dass man nichts übersehen hat. Jetzt sagt der Compiler jede einzelne Stelle, die geändert werden muss.
API-Mismatches zur Build-Zeit erkannt. Wir nutzen zod-Schemas zur Laufzeitvalidierung und TypeScript-Interfaces für Compile-Time-Sicherheit.
Was schwieriger war als erwartet
Third-Party-Typings. Einige Bibliotheken hatten veraltete oder unvollständige Typdefinitionen.
Team-Buy-in. Nicht jeder war begeistert. Ein Senior Developer fand, TypeScript sei "Java in Verkleidung." Es brauchte ein paar Wochen, bis das ganze Team überzeugt war.
Generische Typen. Unsere gemeinsame Komponentenbibliothek brauchte Generics — Table<T>, Select<TOption> — und diese korrekt zu tippen war echt schwierig.
Die Zahlen nach 6 Monaten
- Produktionsfehler durch Typfehler: 12/Monat → 0-1/Monat
- Durchschnittliche PR-Review-Zeit: 45 Min → 25 Min
- Onboarding-Zeit für neue Entwickler: 5 Tage → 2-3 Tage
- Entwicklerzufriedenheit: stieg von 6,2 auf 8,4/10
Die Migration dauerte etwa 4 Monate bis zu 90% Abdeckung. Wir sind jetzt bei 98%.
Was ich anders machen würde
Mit strict: true starten. Wir begannen mit strict: false, mussten aber einen zweiten Durchlauf machen.
Früher in gemeinsame Typen investieren. Unsere größten Erfolge kamen von einer einzigen Wahrheitsquelle für Typen.
Testdateien nicht zuletzt migrieren. Wir haben Testdateien zum Schluss gelassen, was bedeutete, dass unsere Tests über Coverage-Abdeckung logen.
Lohnt es sich?
Für jedes Projekt mit mehr als einem Entwickler und einer Lebensdauer von über 6 Monaten — absolut. TypeScript verhindert nicht alle Bugs, aber eliminiert eine ganze Kategorie davon.
Die Migrationskosten waren etwa 15% unserer Velocity für 4 Monate. Der Ertrag ist permanent und kumulativ.