Menu

TypeScript instanceof: Klassen und Errors einengen

instanceof prüft zur Laufzeit, ob ein Objekt von einer Klasse erzeugt wurde, und TypeScript engt die Variable auf diese Klasse ein. Wie das mit eigenen Klassen und Error-Unterklassen funktioniert, warum es keine Interfaces oder Typaliasse prüfen kann und wo es überraschende Antworten gibt.

Diese Seite enthält ausführbare Editoren - bearbeiten, ausführen und Ausgabe sofort sehen.

value instanceof SomeClass ist eine JavaScript-Prüfung, die zur Laufzeit läuft: Sie ist true, wenn SomeClass.prototype in der Prototypkette des Objekts liegt, das Objekt also mit new SomeClass (oder einer Unterklasse) erzeugt wurde. TypeScript engt value innerhalb der Prüfung auf SomeClass ein.

Nimm instanceof für Objekte aus Klassen und typeof für primitive Werte. Hier braucht es beides: instanceof trennt das Date ab, dann teilt typeof den Rest auf.

Eigene Klassen einengen

instanceof engt im Zweig true auf die Klasse ein und entfernt sie im Zweig false, eine Union aus Klassen lässt sich also Member für Member behandeln.

Eine Instanz einer Unterklasse besteht auch die Prüfung auf ihre Elternklasse: Wenn Square extends Rect gilt, ist new Square(2) instanceof Rect gleich true. Prüfe die spezifischste Klasse zuerst, wenn sich die Zweige unterscheiden.

Error-Unterklassen in catch

Am häufigsten wird instanceof in catch verwendet. Unter strict ist der gefangene Wert unknown (alles kann geworfen werden), und mit instanceof kommst du zu einem typisierten Fehler zurück.

Ausgabe:

404: /missing.txt
TypeError: path must be absolute

class X extends Error funktioniert mit instanceof auf jedem Target, das TypeScript 7 unterstützt (ES2015 und neuer). Der ältere Rat, im Konstruktor Object.setPrototypeOf(this, X.prototype) aufzurufen, galt für Code, der nach ES5 kompiliert wurde, ein Target, das TypeScript 7 entfernt hat.

instanceof funktioniert nicht mit Interfaces oder Typen

Interfaces und Typaliasse existieren nur für den Compiler. Nach dem Kompilieren gibt es keinen Wert User, mit dem verglichen werden könnte, also verweigert TypeScript die Prüfung:

Der Compiler meldet index.ts(8,24): error TS2693: 'User' only refers to a type, but is being used as a value here. Es gibt zwei Lösungen. Prüfe die Form selbst mit einem Type Guard, einer Funktion, die value is User zurückgibt:

Oder, wenn dein Code diese Objekte erzeugt, mach User zu einer Klasse und erzeuge die Objekte mit new; dann funktioniert instanceof. Die Seite zu Type Guards behandelt Predicates und Assertion-Funktionen im Detail.

Der richtige Typ ist nicht die richtige Instanz

TypeScript vergleicht Typen nach ihrer Struktur: Ein Objektliteral mit denselben Membern wie eine Klasse ist dem Klassentyp zuweisbar. instanceof schaut nicht auf die Struktur. Es durchläuft die Prototypkette, und ein Objekt, das nie mit new erzeugt wurde, besteht die Prüfung nicht, auch wenn der Compiler es als diesen Typ akzeptiert.

Die letzte Zeile ist wichtig. structuredClone, JSON.parse(JSON.stringify(...)) und Nachrichten zwischen Workern liefern alle einfache Objekte ohne den Prototyp der Klasse, auch wenn ihr statischer Typ weiterhin Point sagen kann. Wenn Klasseninstanzen eine solche Grenze überqueren, baue sie neu (new Point(copy.x, copy.y)), bevor du dich auf instanceof oder auf Methoden verlässt.

instanceof und primitive Werte

Primitive Werte (string, number, boolean...) sind keine Objekte und haben keine Prototypkette, daher ist "hi" instanceof String gleich false. TypeScript markiert den Fehler, wenn es kann: Mit einem als string typisierten Wert auf der linken Seite ist instanceof der Fehler TS2358, The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter. Nimm für primitive Werte typeof.

WertPrüfung mit instanceofErgebnis
new Date()instanceof Datetrue
[1, 2]instanceof Arraytrue (aber lieber Array.isArray)
new TypeError("x")instanceof Errortrue (Unterklasse)
{ x: 1, y: 2 }instanceof Pointfalse (nie konstruiert)
Object.create(null)instanceof Objectfalse (kein Prototyp)
"hi"instanceof Stringfalse (primitiver Wert)

Werte aus anderen Realms

instanceof vergleicht mit einem bestimmten Konstruktorobjekt. Code in einem anderen Realm (einem iframe oder einem vm-Kontext in Node) hat eigene Array, Error und Date, ein dort erzeugtes Array besteht hier also instanceof Array nicht. Dasselbe passiert, wenn zwei Kopien eines npm-Pakets in node_modules landen: Jede Kopie hat ihre eigene Klasse, und eine Instanz der einen besteht instanceof gegen die andere nicht. Für Arrays funktioniert Array.isArray über Realms hinweg. Für deine eigenen Typen vermeidet eine Prüfung auf eine Eigenschaft (ein Type Guard oder ein Feld kind) das Problem ganz.

Häufig gestellte Fragen

Wie prüfe ich in TypeScript, ob ein Objekt eine Instanz einer Klasse ist?

Mit value instanceof ClassName. Das ist eine Prüfung zur Laufzeit (reines JavaScript), und TypeScript engt value im if auf ClassName ein. Es funktioniert mit eingebauten Klassen wie Date, Map und Error ebenso wie mit deinen eigenen.

Kann ich instanceof in TypeScript mit einem Interface verwenden?

Nein. Interfaces und Typaliasse werden beim Kompilieren zu JavaScript entfernt, zur Laufzeit gibt es also nichts, wogegen geprüft werden könnte. x instanceof User mit einem Interface User ist der Fehler TS2693, "'User' only refers to a type, but is being used as a value here." Prüfe stattdessen die Eigenschaften mit einer Type-Guard-Funktion, oder mach User zu einer Klasse, wenn du die Objekte selbst erzeugst.

Warum gibt instanceof false für ein Objekt des richtigen Typs zurück?

TypeScript-Typen sind strukturell: Ein Objektliteral { x: 1, y: 2 } ist einem Klassentyp Point zuweisbar, wenn es dieselben Member hat. Aber instanceof prüft die Prototypkette, und das Literal wurde nie mit new Point erzeugt, also ist das Ergebnis false. Dasselbe passiert mit Klasseninstanzen, die durch JSON, structuredClone oder einen Message Channel gegangen sind: Sie kommen als einfache Objekte zurück.

Funktioniert instanceof in TypeScript mit eigenen Error-Klassen?

Ja, mit jedem modernen Target. Nach class NotFound extends Error {} ist err instanceof NotFound gleich true. Das alte Problem, bei dem es false zurückgab, betraf nur Ausgaben, die nach ES5 kompiliert wurden, und TypeScript 7 unterstützt das Target ES5 nicht mehr.

Warum ist "hello" instanceof String false?

Ein String-Literal ist ein primitiver Wert, kein Objekt, und hat daher keine Prototypkette, die geprüft werden könnte. instanceof String ist nur für Wrapper-Objekte wahr, die mit new String() erzeugt wurden. TypeScript lehnt instanceof auf einem als string typisierten Wert ab (TS2358); nimm typeof value === "string" für primitive Werte.

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S