Im Gegensatz zu vielen objektorientierten Sprachen implementiert TypeScript die strukturelle Typisierung (duck typing): Ein Objekt gilt als kompatibel zu einem Typ, wenn es alle erforderlichen Eigenschaften hat, unabhängig davon, ob es explizit als dieser Typ deklariert wurde.
Diese Flexibilität führt manchmal dazu, dass Objekte unerwartet als Typ akzeptiert werden, wenn die Struktur übereinstimmt, auch wenn sie tatsächlich nicht semantisch verbunden sind. Dies kann bei komplexen Datenmodellen gefährlich sein, wenn die Struktur zufällig übereinstimmt.
Strukturieren Sie die Typen von Objekten immer korrekt, minimieren Sie strukturelle Übereinstimmungen zwischen verschiedenen Entitäten und verwenden Sie in kritischen Fällen zusätzliche Eigenschaften oder Symbole zur "Nominierung" von Typen.
Beispielcode:
interface Point { x: number; y: number; } interface Pixel { x: number; y: number; } function drawPoint(p: Point) { console.log(p.x, p.y); } const pixel: Pixel = { x: 1, y: 2 }; drawPoint(pixel); // OK, die Typen sind strukturell kompatibel
Schlüsselfeatures:
Wenn die Struktur zweier Interfaces übereinstimmt, bedeutet das, dass sie vollständig austauschbar sind?
Möglicherweise nach der Struktur, aber nicht nach der Logik des Programms. Dies ist auf der Ebene des Compilers zulässig, kann jedoch zu logischen Fehlern führen (z. B. Point und Pixel oben).
Kann man die strukturelle Kompatibilität für einen bestimmten Typ verbieten?
Komplett nein, aber man kann eine einzigartige Eigenschaft (z. B. mit einem Symbol) hinzufügen:
interface Brand { _brand: unique symbol; }
Jetzt kann ein anderes Objekt diesen Typ nicht imitieren, ohne dass es ein gleiches einzigartiges Symbol hat.
Wie unterscheidet sich die strukturelle Typisierung von der nominativen?
Strukturell – basierend auf dem Vorhandensein von Struktur, nominativ – basierend auf dem Übereinstimmen des Namens des Typs im bestimmten Namespace. In TS wird standardmäßig immer strukturelle Typisierung verwendet.
In mehreren Entitäten haben sich unbeabsichtigt Felder überschneidet (z. B. User und Admin wie {id: number, name: string}), was zu Verwirrung bei der Arbeit mit API-Verträgen führte.
Vorteile:
Nachteile:
Verwendung einzigartiger „Marken“ von Symbolen und nicht-standardisierten Feldern zur Unterscheidung semantisch unterschiedlicher Typen mit identischer Struktur.
Vorteile:
Nachteile: