Zum Inhalt springen

1.5 TypeScript: Typen als Werkzeug

Zu Zen-Modus wechseln

Nach dieser Einheit kannst du:

  • erklären, welche Fehlerklasse TypeScript vor dem Programmlauf abfängt und warum zur Laufzeit trotzdem gewöhnliches JavaScript läuft.
  • Daten mit Annotationen, interface und Union Types beschreiben.
  • TypeScript mit tsc und tsx ausführen und begründen, warum erst npm run typecheck die Typen beweist.

Erinnere dich an den Paketdienst aus Einheit 1.1: Er prüft jedes Etikett am Förderband, bevor der Lkw losfährt, oder er stellt einfach zu und hofft, dass sich die Empfängerin schon meldet, wenn etwas nicht stimmt. Bisher hast du mit JavaScript nach der zweiten Methode gearbeitet. Ab dieser Einheit kommt die Kontrolle am Förderband dazu.

Zwei Abläufe beim Paketdienst. Variante 1: Jedes Paket läuft über eine Kontrolle am Förderband, ein falsches Etikett fällt dort auf, bevor der Lkw losfährt. Variante 2: Ohne Kontrolle geht das Paket direkt auf den Lkw, der Fehler fällt erst bei der Empfängerin auf
Abb. 1.1: Vorher prüfen oder nachher hoffen: TypeScript arbeitet wie Variante 1, JavaScript wie Variante 2 (eigene Darstellung).

Diese Einheit zeigt, welche Fehler die Kontrolle findet, wie du Daten so beschreibst, dass sie prüfbar werden, und mit welchen Werkzeugen TypeScript-Code geprüft und gestartet wird. Am Ende setzt ein vollständiges Beispiel die Bausteine zusammen.

  • Compiler (tsc): übersetzt TypeScript in JavaScript und meldet dabei Typfehler.
  • Typannotation: eine Typangabe im Code, etwa : number hinter einem Parameter.
  • Typinferenz: TypeScript erschließt einen Typ selbst, wo er aus dem Code ersichtlich ist.
  • Interface: beschreibt die Form eines Objekts, also Felder und ihre Typen.
  • Union Type: ein Typ, der eine von mehreren aufgezählten Möglichkeiten erlaubt.
  • Generic: ein Typ mit Platzhalter, der beim Verwenden durch einen echten Typ ersetzt wird.

JavaScript prüft Typen erst zur Laufzeit, und ist dann (sehr, sehr) tolerant:

function totalDuration(clips) {
return clips.reduce((sum, clip) => sum + clip.durationSeconds, 0);
}
totalDuration([{ filename: "intro.mp4", durationSecond: 90 }]); // NaN

Beispielprojekt: 01_typescript_examples/ex15_js_without_types

Der Tippfehler durationSecond (ohne s) fällt nicht auf: Der Zugriff liefert undefined, die Addition NaN, und das Programm läuft mit diesem Unsinn weiter. Solche Fehler kosten in wachsenden Projekten die meiste Debugging-Zeit.

Genau gegen sie ist TypeScript gebaut: JavaScript plus Typangaben, geprüft vor dem Programmlauf vom Compiler tsc. TypeScript wird zu gewöhnlichem JavaScript übersetzt; im Browser und in Node läuft am Ende immer JavaScript.

Zurück zum Paketdienst vom Anfang dieser Einheit: tsc ist die Kontrolle am Förderband. Sie findet das falsch beschriftete Paket, solange es noch in der Halle steht - nicht erst, wenn die Kundin (oder der Benutzer deiner Anwendung) es auspackt. Die Grenze des Bildes: Die Kontrolle liest nur Etiketten, die im eigenen Lager geklebt wurden. Was von außen kommt, etwa die Antwort eines Servers, hat für tsc kein Etikett; wie man damit umgeht, zeigt Einheit 1.6.

Ablauf: timecode.ts wird von tsc geprüft; Typfehler werden vor dem Start gemeldet, danach entsteht timecode.js ohne Typen, das Node.js oder der Browser ausführt
Abb. 1.13: Typen existieren nur zur Compile-Zeit. Zur Laufzeit ist nur noch JavaScript übrig (eigene Darstellung).
function totalDuration(clips: Clip[]): number {
return clips.reduce((sum, clip) => sum + clip.durationSeconds, 0);
}
let attempts: number = 0; // explicit
let name = "Ada"; // inferred as string; annotation unnecessary

Die Syntax folgt dem Muster wert: Typ, der Rückgabetyp steht nach der Parameterliste. TypeScript inferiert Typen, wo es sie sehen kann; annotiert werden vor allem Funktionsparameter und Datenstrukturen, nicht jede lokale Variable.

interface Clip {
filename: string;
durationSeconds: number;
tags: string[];
fps?: number; // optional property
}
const intro: Clip = {
filename: "intro.mp4",
durationSeconds: 90,
tags: ["opener"],
};

Beispielprojekt: 01_typescript_examples/ex16_annotations_interfaces

Ein interface beschreibt die Form eines Objekts: welche Felder, welche Typen, was optional ist (?). Der Tippfehler von oben ist damit ein Compile-Fehler mit präziser Meldung, noch bevor das Programm startet: 'durationSecond' does not exist in type 'Clip'. Did you mean to write 'durationSeconds'? Interfaces sind zugleich Dokumentation: Wer Clip liest, kennt den Datenvertrag, ohne Code zu lesen. Genau in dieser Rolle begleiten sie das ganze Jahr, als Verträge für API-Daten.

Links das Interface Clip mit filename, durationSeconds und tags. Rechts ein Objekt mit dem Tippfehler durationSecond. tsc vergleicht beide und meldet vor dem Start den Fehler TS2561: durationSecond existiert im Typ Clip nicht, gemeint ist wohl durationSeconds
Abb. 1.14: Das Interface ist der Vertrag; tsc prüft jedes Objekt dagegen (eigene Darstellung).
type RenderState = "queued" | "running" | "done" | "failed";
function label(state: RenderState): string {
if (state === "done") return "finished";
return state;
}
label("dne"); // compile error: not assignable to RenderState

Beispielprojekt: 01_typescript_examples/ex17_union_types

Ein Union Type zählt die erlaubten Möglichkeiten auf. Der Klassiker sind Zustands- und Statusfelder: Statt beliebiger Strings gibt es vier gültige Werte, und jeder Tippfehler fliegt beim Kompilieren auf. Auch Kombinationen wie string | null (“String oder bewusst leer”) sind Union Types; TypeScript zwingt dann an jeder Verwendungsstelle zur Behandlung des null-Falls.

Terminal-Fenster
npm install --save-dev typescript tsx
npx tsc --init # creates tsconfig.json
npx tsc # type-check and compile to JavaScript
npx tsx timecode.ts # run directly during development (tsx package)

Im Alltag dieses Jahres übernimmt Next.js die komplette TypeScript-Werkzeugkette unsichtbar; tsc von Hand zu bedienen gehört trotzdem einmal erlebt, damit klar ist, was das Framework automatisiert. In der tsconfig.json bleibt die Voreinstellung "strict": true unangetastet: Der strenge Modus findet die meisten Fehler, und sich später an Strenge zu gewöhnen ist erfahrungsgemäß viel schwerer. npx tsc --init (TypeScript 7) schaltet außerdem noUncheckedIndexedAccess ein: Ein Array-Zugriff wie items[0] hat dann den Typ T | undefined, weil das Array leer sein könnte. Dazu kommt exactOptionalPropertyTypes, das bei einem optionalen Feld wie fps?: number ein ausdrücklich zugewiesenes undefined verbietet; der Kurs behält beide Einstellungen bei.

Wo begegnet dir das? Schon in deinem Editor: VS Code ist selbst in TypeScript geschrieben, und die roten Unterstreichungen in .ts-Dateien kommen von demselben Compiler, den du mit tsc startest. Auch create-next-app aus Kapitel 8 schlägt TypeScript als Voreinstellung vor.

Auflösung

Auch hier meldet tsc einen Fehler: Argument of type 'string' is not assignable to parameter of type 'RenderState'. Der Compiler kennt nur den Typ string der Variablen, nicht ihren Wert, und nicht jeder String ist ein gültiger Zustand. Erst eine Prüfung (etwa if (input === "done" || input === "queued" ...)) grenzt den Typ ein. Genau dieses Prüfen statt Behaupten ist das Thema von Einheit 1.6.

Ein kleines typisiertes Werkzeug, das die Bausteine kombiniert: Aus einer Liste von Videoclips soll die Gesamtdauer je Tag berechnet werden.

interface Clip {
filename: string;
durationSeconds: number;
tags: string[];
}
function durationByTag(clips: Clip[]): Map<string, number> {
const totals = new Map<string, number>();
for (const clip of clips) {
for (const tag of clip.tags) {
totals.set(tag, (totals.get(tag) ?? 0) + clip.durationSeconds);
}
}
return totals;
}
const clips: Clip[] = [
{ filename: "intro.mp4", durationSeconds: 90, tags: ["opener"] },
{ filename: "interview.mp4", durationSeconds: 845, tags: ["main", "voice"] },
{ filename: "outro.mp4", durationSeconds: 45, tags: ["opener"] },
];
for (const [tag, seconds] of durationByTag(clips)) {
console.log(`${tag}: ${seconds} s`);
}

Beispielprojekt: 01_typescript_examples/ex19_duration_by_tag

Beachtenswert: das Interface als Datenvertrag, Map<string, number> als Generic in Verwendung, ?? 0 für den ersten Treffer eines Tags und Destructuring in der Ausgabeschleife. Jeder Tippfehler in einem Feldnamen wäre ein Compile-Fehler.

Drei Clips: intro.mp4 mit 90 Sekunden und dem Tag opener, interview.mp4 mit 845 Sekunden und den Tags main und voice, outro.mp4 mit 45 Sekunden und dem Tag opener. Jeder Tag zählt die Dauer seines Clips in die Map ein: opener 135, main 845, voice 845
Abb. 1.15: Eine Map sammelt die Dauer je Tag (eigene Darstellung).

Wo begegnet dir das? Summieren nach einem Merkmal ist eine der häufigsten Auswertungen überhaupt: Ausgaben je Kategorie in einer Banking-App, Bildschirmzeit je App in den Handy-Einstellungen, Spielzeit je Spiel auf einer Gaming-Plattform. Das Prinzip ist jedes Mal dasselbe wie in durationByTag: eine Schleife über die Einträge und eine Map vom Merkmal auf die laufende Summe.

  1. undefined statt Fehler: In JavaScript liefert der Zugriff auf ein nicht existierendes Feld undefined und knallt erst später. In TypeScript wird daraus ein Compile-Fehler; einer der Hauptgründe für die Sprache.
  2. Programm läuft, also stimmen die Typen: tsx startet auch Dateien mit Typfehlern. Erst npm run typecheck (tsc --noEmit) beweist, dass der Compiler zufrieden ist.
  3. Wert und Typ verwechselt: Bei const input: string = "done"; kennt der Compiler nur den Typ string, nicht den Wert. Ein Union Type wie RenderState nimmt die Variable deshalb erst nach einer Prüfung an.
  4. strict abgeschaltet: Wer Fehlermeldungen loswerden will, indem er in der tsconfig.json den strengen Modus abdreht, verliert genau die Prüfungen, für die TypeScript da ist. Die Voreinstellung bleibt.
  • TypeScript-Handbuch - die offizielle, gut lesbare Referenz; das Kapitel Everyday Types deckt diese Einheit fast vollständig ab.
  • TypeScript-Handbuch: Everyday Types - Annotationen, Inferenz, Interfaces, Union Types und Literal-Typen an einem Stück.
  • TypeScript Playground - TypeScript im Browser ausprobieren, ohne Installation; rechts siehst du sofort das erzeugte JavaScript und alle Compiler-Meldungen.

Du kannst dir diese Einheit kostenlos mit der Vorlesefunktion deines Browsers oder Betriebssystems vorlesen lassen (etwa „Laut vorlesen” in Edge), ohne Konto und ohne Upload; die Codebeispiele liest du dabei am Bildschirm mit. Freiwillig kannst du mit Google NotebookLM (Google-Konto nötig) aus diesem öffentlichen Text eine gesprochene Zusammenfassung erzeugen, auch auf Deutsch.

Du kannst jetzt:

  • erklären, welche Fehlerklasse TypeScript vor dem Programmlauf abfängt und warum zur Laufzeit trotzdem gewöhnliches JavaScript läuft.
  • Daten mit Annotationen, interface und Union Types beschreiben.
  • TypeScript mit tsc und tsx ausführen und begründen, warum erst npm run typecheck die Typen beweist.
  • Aufgabe 02 - Typen retten den Tag, Stufen Wesentlich_überwiegend und Wesentlich_vollständig
  • Aufgabe 03 - TypeScript-Katas, Stufen Wesentlich_überwiegend und Wesentlich_vollständig
  • VS Code ist in TypeScript geschrieben → microsoft/vscode auf GitHub
  • create-next-app legt standardmäßig ein TypeScript-Projekt an → Next.js-Dokumentation: create-next-app
  • Typannotationen, Inferenz, Interfaces, Union Types → TypeScript-Handbuch: Everyday Types
  • TypeScript 7: Voreinstellungen von tsc --init (noUncheckedIndexedAccess, exactOptionalPropertyTypes), Meldung TS2561 → eigener Test mit TypeScript 7.0.2 (Oktober 2026); TSConfig-Referenz: noUncheckedIndexedAccess
  • TypeScript allgemein, tsc und tsconfig.json → TypeScript-Handbuch, TypeScript Playground
  • Abb. 1.1 (Paketdienst), Abb. 1.13 (Kontrolle am Förderband: tsc vor dem Programmlauf), Abb. 1.14 (Interface als Vertrag), Abb. 1.15 (Map je Tag) → eigene Darstellung
  • Oliver Maurhart (MAO)
  • Michael Gabriel (GAM)

CC-BY-SA

https://qiz.at/rules