🧩Das Typsystem

Ein Typ ist eine Menge möglicher Werte. string umfasst alle Texte, "hallo" genau einen, never keinen. Mit diesem Bild lassen sich fast alle Regeln des Typsystems erklären.

🧱Grundtypen

TypBeispielWerteHinweis
stringlet name: string = "Ada";alle TexteKlein geschrieben! String (groß) ist der Wrapper-Objekttyp.
numberlet preis: number = 9.99;Gleitkommazahlen (IEEE 754) inkl. NaN, InfinityEs gibt kein separates int.
bigintlet gross: bigint = 2n ** 64n;beliebig große GanzzahlenNicht mit number mischbar.
booleanlet aktiv: boolean = true;true, falseIntern die Union true | false.
null / undefinedlet leer: null = null;je genau ein WertMit strictNullChecks eigene Typen, sonst in jedem Typ enthalten.
symbollet id: symbol = Symbol("id");eindeutige Schlüsselunique symbol für Konstanten.
T[] / Array<T>let zahlen: number[] = [1, 2, 3];Listen beliebiger LängeBeide Schreibweisen sind gleichwertig.
[A, B]let paar: [string, number] = ["x", 1];Tupel: feste Länge, Typ pro PositionMit Namen: [name: string, alter: number].
object / { … }let p: { x: number; y: number } = { x: 1, y: 2 };Objekte mit dieser Strukturobject = alles Nicht-Primitive.
(a: A) => Rlet f: (n: number) => string = String;FunktionenParameternamen sind nur Dokumentation.
voidfunction log(): void {}„kein sinnvoller Rückgabewert“Nur als Rückgabetyp üblich.

🎭any, unknown und never

Drei Sonderfälle: unknown ist die Menge aller Werte (oben), never die leere Menge (unten). any steht außerhalb – es ist in beide Richtungen zuweisbar und schaltet die Prüfung ab.
                 unknown          ← alle Werte ("top type")
        ┌───────────┼─────────────┬──────────┐
     object       string        number    null  undefined …
        │           │             │
   { x: 1 } …    "hallo" …        42 …    ← Literal-Typen
        └───────────┼─────────────┘
                  never           ← kein Wert ("bottom type")

     any  = „Typprüfung aus“: passt überall hin und nimmt alles an
TypeScript · bearbeitbar, Maus über Namen zeigt Typen

Zuweisbarkeit – berechnet vom Compiler

Wert vom Typ … ↓ · … zuweisbar an →anyunknownneverstring"hallo"numbernullundefinedobject{}
any··········
unknown··········
never··········
string··········
"hallo"··········
number··········
null··········
undefined··········
object··········
{}··········

Fahren Sie über eine Zelle.

  • Spalte unknown: alles grün – jeder Wert passt hinein.
  • Zeile never: alles grün – die leere Menge ist Teilmenge von allem.
  • {} heißt „alles außer null/undefined“ – nicht „leeres Objekt“.

🔤Literal-Typen & Widening

Ein Literal-Typ enthält genau einen Wert. Ob TypeScript den genauen oder einen „verbreiterten“ Typ ableitet, hängt davon ab, ob sich der Wert später ändern kann.
CodeTyp laut CompilerWarum?
let a = "hallo";…let kann sich ändern → der Literal-Typ wird zu string verbreitert (Widening).
const b = "hallo";…const ändert sich nie → der Typ bleibt das Literal "hallo".
const c = 42;…Auch Zahlen können Literal-Typen sein.
const d = { modus: "hell" };…Eigenschaften sind veränderbar → modus wird string.
const e = { modus: "hell" } as const;…as const friert alles ein: readonly und Literal-Typen.
const f = [1, 2, 3];…Array-Literal → number[].
const g = [1, 2, 3] as const;…Mit as const ein schreibgeschütztes Tupel.
let h: "hell" | "dunkel" = "hell";…Eine Union von Literalen als erlaubte Werteliste.

⭕Union & Intersection als Mengen

A | B vereinigt die Wertemengen, A & B schneidet sie. Wählen Sie zwei Typen – Ergebnis und Diagramm kommen vom Compiler.
unknown – alle WerteAB

Compiler rechnet …

Vereinigung · A | B · „das eine oder das andere“
…

Alle Werte, die zu A oder B passen. Man darf nur verwenden, was alle Mitglieder gemeinsam haben – bis man eingrenzt (Narrowing).

Schnitt · A & B · „beides zugleich“
…

Nur Werte, die zu A und B passen. Bei primitiven Typen bleibt oft wenig übrig (oder never).

Berechnet vom Compiler aus: type Vereinigung = string | number | number | boolean; type Schnitt = (string | number) & (number | boolean);
💡 Paradox bei Objekten?
MitName & MitAlter hat mehr Eigenschaften als jeder Teil – beschreibt aber weniger Werte (nur Objekte mit beiden Eigenschaften). Bei der Union ist es umgekehrt: mehr Werte, aber sicher nutzbar sind nur gemeinsame Eigenschaften, bis man mitin eingrenzt.
TypeScript · bearbeitbar, Maus über Namen zeigt Typen

🦆Strukturelle Typisierung

TypeScript vergleicht Typen nach ihrer Form, nicht nach ihrem Namen („Duck Typing“): Wer mindestens die geforderten Eigenschaften hat, passt – egal wie sein Typ heißt.
TypeScript · bearbeitbar, Maus über Namen zeigt Typen
⚠️ Ausnahme: frische Objektliterale
Direkt geschriebene Objektliterale mit zusätzlichen Eigenschaften lehnt der Compiler ab (Excess Property Check, TS2353) – obwohl sie strukturell passen würden. Das fängt Tippfehler ab.
Wert vom Typ … ↓ · … zuweisbar an →Punkt2DPunkt3DBenanntBenannterPunktOptionalZLeer
Punkt2D······
Punkt3D······
Benannt······
BenannterPunkt······
OptionalZ······
Leer······

Fahren Sie über eine Zelle.

Punkt3D passt an Punkt2D (hat x und y – und mehr), umgekehrt nicht. An Leer passt alles, weil nichts verlangt wird.

⚖️interface oder type?

Für Objektformen sind beide fast austauschbar. Die Unterschiede:
Merkmalinterfacetype
Objektform beschreiben✅ interface P { x: number }✅ type P = { x: number }
Erweitern✅ interface B extends A { … }✅ type B = A & { … }
Unions, Tupel, Primitive❌✅ type Id = string | number
Mapped/Conditional Types❌✅
Declaration Merging (zweimal deklarieren = zusammenführen)✅ z. B. um globale Typen zu ergänzen❌ Fehler: Doppelter Bezeichner
Von Klassen implementierbar✅✅ (wenn Objekttyp)
Declaration Merging · bearbeitbar, Maus über Namen zeigt Typen

🔒Optionale und readonly-Eigenschaften

? erlaubt, dass eine Eigenschaft fehlt (ihr Typ enthält dann undefined). readonly verbietet Zuweisungen nach dem Erzeugen – nur zur Compile-Zeit.
TypeScript · bearbeitbar, Maus über Namen zeigt Typen
JavaScript (erzeugt von tsc) · …nur lesen