Menu

instanceof en TypeScript : affiner les classes et les erreurs

instanceof vérifie à l'exécution si un objet a été créé par une classe, et TypeScript affine la variable vers cette classe. Comment il fonctionne avec vos propres classes et les sous-classes d'Error, pourquoi il ne peut pas vérifier les interfaces ni les alias de type, et où il donne des réponses surprenantes.

Cette page contient des éditeurs exécutables - modifiez, exécutez et voyez la sortie instantanément.

value instanceof SomeClass est une vérification JavaScript qui s'exécute : elle vaut true quand SomeClass.prototype se trouve dans la chaîne de prototypes de l'objet, c'est-à-dire quand l'objet a été créé avec new SomeClass (ou une sous-classe). TypeScript affine value en SomeClass à l'intérieur de la vérification.

Utilisez instanceof pour les objets créés à partir de classes, et typeof pour les primitives. Ici, les deux sont nécessaires : instanceof isole le Date, puis typeof sépare ce qui reste.

Affiner vos propres classes

instanceof affine vers la classe dans la branche true et la retire dans la branche false : une union de classes peut donc être traitée membre par membre.

Une instance de sous-classe passe aussi la vérification de son parent : si Square extends Rect, alors new Square(2) instanceof Rect vaut true. Testez d'abord la classe la plus précise quand les branches diffèrent.

Les sous-classes d'Error dans catch

L'usage le plus courant d'instanceof se trouve dans catch. Avec strict, la valeur capturée est unknown (on peut lever n'importe quoi), et instanceof est le moyen de retrouver une erreur typée.

Sortie :

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

class X extends Error fonctionne avec instanceof sur toutes les cibles que prend en charge TypeScript 7 (ES2015 et ultérieures). L'ancien conseil d'appeler Object.setPrototypeOf(this, X.prototype) dans le constructeur s'appliquait au code compilé en ES5, une cible que TypeScript 7 a supprimée.

instanceof ne fonctionne pas avec les interfaces ni les types

Les interfaces et les alias de type n'existent que pour le compilateur. Après la compilation, il n'y a aucune valeur User à laquelle comparer, TypeScript refuse donc la vérification :

Le compilateur signale index.ts(8,24): error TS2693: 'User' only refers to a type, but is being used as a value here. Il y a deux corrections. Vérifiez vous-même la forme avec un type guard, une fonction qui renvoie value is User :

Ou, si votre code crée ces objets, faites de User une classe et construisez-les avec new ; instanceof fonctionne alors. La page type guards présente en détail les prédicats et les fonctions d'assertion.

Le bon type n'est pas la bonne instance

TypeScript compare les types par leur structure : un littéral objet qui a les mêmes membres qu'une classe est assignable au type de cette classe. instanceof ne regarde pas la structure. Il parcourt la chaîne de prototypes, et un objet qui n'a jamais été créé avec new échoue même si le compilateur l'accepte comme ce type.

La dernière ligne compte. structuredClone, JSON.parse(JSON.stringify(...)) et les messages entre workers renvoient tous des objets simples sans le prototype de la classe, même si leur type statique peut encore indiquer Point. Quand des instances de classes franchissent une telle frontière, reconstruisez-les (new Point(copy.x, copy.y)) avant de compter sur instanceof ou sur les méthodes.

instanceof et les primitives

Les primitives (string, number, boolean...) ne sont pas des objets et n'ont pas de chaîne de prototypes : "hi" instanceof String vaut donc false. TypeScript signale l'erreur quand il le peut : avec une valeur typée string à gauche, instanceof provoque l'erreur TS2358, The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter. Utilisez typeof pour les primitives.

ValeurVérification instanceofRésultat
new Date()instanceof Datetrue
[1, 2]instanceof Arraytrue (mais préférez Array.isArray)
new TypeError("x")instanceof Errortrue (sous-classe)
{ x: 1, y: 2 }instanceof Pointfalse (jamais construit)
Object.create(null)instanceof Objectfalse (pas de prototype)
"hi"instanceof Stringfalse (primitive)

Valeurs venues d'un autre realm

instanceof compare à un objet constructeur précis. Du code exécuté dans un autre realm (une iframe, ou un contexte vm de Node) a ses propres Array, Error et Date : un tableau créé là-bas échoue donc à instanceof Array ici. La même chose se produit quand deux copies d'un même paquet npm se retrouvent dans node_modules : chaque copie a sa propre classe, et une instance de l'une échoue à instanceof face à l'autre. Pour les tableaux, Array.isArray fonctionne d'un realm à l'autre. Pour vos propres types, vérifier une propriété (un type guard, ou un champ kind) évite complètement le problème.

Questions fréquentes

Comment vérifier qu'un objet est une instance d'une classe en TypeScript ?

Utilisez value instanceof ClassName. C'est une vérification à l'exécution (du JavaScript pur), et TypeScript affine value en ClassName dans le if. Cela fonctionne pour les classes intégrées comme Date, Map et Error ainsi que pour les vôtres.

Peut-on utiliser instanceof avec une interface en TypeScript ?

Non. Les interfaces et les alias de type sont effacés quand TypeScript compile en JavaScript : il n'y a donc rien à quoi comparer à l'exécution. x instanceof User avec une interface User provoque l'erreur TS2693, « 'User' only refers to a type, but is being used as a value here. » Vérifiez plutôt les propriétés avec une fonction type guard, ou faites de User une classe si c'est vous qui créez les objets.

Pourquoi instanceof renvoie-t-il false pour un objet du bon type ?

Les types TypeScript sont structurels : un littéral objet { x: 1, y: 2 } est assignable au type d'une classe Point s'il a les mêmes membres. Mais instanceof vérifie la chaîne de prototypes, et le littéral n'a jamais été créé avec new Point, donc le résultat est false. Il en va de même pour les instances de classes passées par JSON, structuredClone ou un canal de messages, qui reviennent sous forme d'objets simples.

instanceof fonctionne-t-il avec des classes Error personnalisées en TypeScript ?

Oui, avec toute cible moderne. class NotFound extends Error {} puis err instanceof NotFound vaut true. L'ancien problème où il renvoyait false ne concernait que la sortie compilée en ES5, et TypeScript 7 ne prend plus en charge la cible ES5.

Pourquoi "hello" instanceof String vaut-il false ?

Un littéral de chaîne est une primitive, pas un objet : il n'a pas de chaîne de prototypes à vérifier. instanceof String n'est vrai que pour les objets enveloppes créés avec new String(). TypeScript refuse instanceof sur une valeur typée string (TS2358) ; utilisez typeof value === "string" pour les primitives.

Coddy programming languages illustration

Apprendre à coder avec Coddy

COMMENCER