Un type guard est une vérification à l'exécution que TypeScript comprend : il affine donc le type dans la branche vérifiée. typeof, instanceof et in sont des guards intégrés ; pour tout le reste, vous écrivez une fonction dont le type de retour est un prédicat de type, value is Type.
isUser renvoie un simple booléen à l'exécution. Le type de retour value is User indique au compilateur ce que prouve un résultat true, et chaque if (isUser(x)) affine alors x en User.
Les type guards intégrés
Ces vérifications affinent sans aucune fonction auxiliaire :
| Guard | Exemple | À utiliser pour |
|---|---|---|
typeof | typeof x === "number" | primitives et fonctions |
instanceof | x instanceof Date | instances de classes |
in | "email" in x | unions d'objets, propriétés d'objets unknown |
Array.isArray | Array.isArray(x) | tableaux |
| Égalité | x === null, x.kind === "circle" | null/undefined, étiquettes littérales |
| Véracité | if (x) | retirer null et undefined |
Tous s'exécutent comme du JavaScript ordinaire. Ce qu'ajoute TypeScript, c'est le narrowing : il lit la vérification et ajuste le type dans chaque branche. La liste complète des formes se trouve sur la page narrowing de types. Un guard personnalisé sert aux vérifications qui ne tiennent pas en une expression, ou que vous voulez réutiliser.
Écrire un prédicat de type
Un prédicat de type a la forme parameterName is Type et remplace boolean comme type de retour. Le narrowing fonctionne dans les deux sens : true affine vers Type, et false retire Type d'une union.
Passer un guard à filter donne un tableau correctement typé. Depuis TypeScript 5.5, le compilateur infère aussi un prédicat à partir des fonctions fléchées simples : pets.filter((p) => p.kind === "cat") renvoie donc Cat[] sans guard nommé.
Le type du prédicat doit correspondre au type du paramètre : function f(x: string): x is number provoque l'erreur TS2677, A type predicate's type must be assignable to its parameter's type.
Le compilateur fait confiance à votre guard
TypeScript vérifie qu'un guard renvoie un booléen. Il ne vérifie pas que ce booléen est juste. Un guard qui renvoie true pour de mauvaises valeurs fait mentir les types, et le programme échoue à l'exécution sans aucune erreur de compilation.
data.price.toFixed(2) lève TypeError: Cannot read properties of undefined (reading 'toFixed') à l'exécution. Le compilateur a accepté data.price comme un number parce que le guard l'affirmait. Vérifiez chaque propriété dont dépend le reste du code, et gardez les guards petits, testés et proches du type qu'ils décrivent.
Vérifier qu'un objet est d'un certain type
C'est la question derrière la plupart des guards personnalisés : des données arrivent en unknown (depuis JSON.parse, fetch, localStorage, un message) et vous devez savoir si elles correspondent à votre interface. La recette :
typeof value === "object" && value !== null(un objet, pasnull)."prop" in valuepour chaque propriété requise. Surunknown,inajoute la propriété au type en tant queunknown.typeof value.prop === "..."(ou un guard imbriqué) pour le type de chaque propriété.Array.isArray(value.items) && value.items.every(isItem)pour les tableaux.
Pour les formes grandes ou profondément imbriquées, écrire ces guards à la main devient fastidieux. Les bibliothèques de schémas comme Zod ou Valibot vous permettent de décrire la forme une seule fois et vous donnent à la fois la vérification à l'exécution et le type TypeScript.
Fonctions d'assertion : asserts value is Type
Une fonction d'assertion lève une exception si la vérification échoue et se termine normalement sinon. Son type de retour est asserts value is Type (ou asserts condition), et tout ce qui vient après l'appel est affiné, sans if.
Une règle fait trébucher : une fonction d'assertion doit être appelée via un nom au type explicite. Une fonction fléchée const sans annotation, const check = (v: unknown): asserts v is string => {...}, provoque l'erreur TS2775 à l'appel, Assertions require every name in the call target to be declared with an explicit type annotation. Utilisez une déclaration function, ou annotez la constante avec un type de fonction.
Guards, assertions ou casts
| Outil | Vérification à l'exécution ? | Affine | En cas d'échec |
|---|---|---|---|
Guard intégré (typeof, in...) | Oui | dans la branche | prend l'autre branche |
Fonction value is T | Oui (votre code) | dans la branche | prend l'autre branche |
Fonction asserts value is T | Oui (votre code) | après l'appel | lève une exception |
value as T | Non | l'expression | rien : le mauvais type se propage |
Une assertion de type (as) change le type sans rien vérifier. À une frontière où les données viennent de l'extérieur, un guard ou une fonction d'assertion est la version sûre de la même idée.
Guards basés sur this dans les classes
Une méthode peut affiner l'objet sur lequel elle est appelée avec this is Type. C'est pratique dans les hiérarchies de classes :
class FileNode {
constructor(public name: string) {}
isDirectory(): this is DirectoryNode {
return this instanceof DirectoryNode;
}
}
class DirectoryNode extends FileNode {
children: FileNode[] = [];
}
function count(node: FileNode): number {
return node.isDirectory() ? node.children.length : 0; // node: DirectoryNode in the true branch
}
Questions fréquentes
Qu'est-ce qu'un type guard en TypeScript ?
Toute vérification à l'exécution que TypeScript utilise pour affiner un type : typeof x === "string", x instanceof Date, "id" in x, Array.isArray(x), ou l'appel d'une fonction dont le type de retour est un prédicat de type comme x is User. Dans la branche vérifiée, la variable a le type plus étroit.
Comment vérifier qu'un objet est d'un certain type en TypeScript ?
Les types n'existent pas à l'exécution, vous vérifiez donc les propriétés : écrivez une fonction isUser(value: unknown): value is User qui teste typeof value === "object", value !== null, et chaque propriété requise avec in et typeof. Après if (isUser(x)), x est typé User. Pour les classes, x instanceof MyClass suffit.
Que signifie « value is Type » en TypeScript ?
C'est un prédicat de type, utilisé comme type de retour d'une fonction. La fonction renvoie toujours un booléen à l'exécution, mais quand elle renvoie true, TypeScript affine l'argument en Type à l'endroit de l'appel, et quand elle renvoie false, il l'affine vers les autres membres de l'union. Le compilateur ne vérifie pas le corps de la fonction : la vérification doit donc être correcte.
Quelle est la différence entre un type guard et une fonction d'assertion ?
Un type guard (x is T) renvoie un booléen et affine dans un if. Une fonction d'assertion (asserts x is T) ne renvoie rien et lève une exception quand la vérification échoue : tout ce qui suit l'appel est donc affiné sans if. Utilisez les guards pour les branchements et les assertions pour « ceci doit être vrai, sinon on s'arrête ».
Peut-on vérifier qu'un objet implémente une interface en TypeScript ?
Pas directement : les interfaces sont effacées et instanceof ne les accepte pas. Écrivez un type guard qui vérifie les propriétés de l'interface, ou ajoutez une propriété étiquette littérale (kind: "user") et comparez-la. Les bibliothèques de schémas comme Zod génèrent à la fois la vérification et le type à partir d'une seule définition.