Skip to content

Affinage de type en TypeScript expliqué

Les moyens par lesquels TypeScript affine un type à l’intérieur d’une branche, regroupés par technique : gardes intégrées, prédicats personnalisés, fonctions d’assertion, unions discriminées, flux d’égalité et de vérité, et affinage par alias ou différé. Chaque ligne associe la technique à un exemple en une ligne.

L’affinage (narrowing) est la façon dont TypeScript transforme un type large en un type plus précis à l’intérieur d’une branche de code, afin de prouver qu’un accès à une propriété est sûr. Chaque vérification (typeof, in, un prédicat, un discriminant) indique au compilateur : à partir d’ici, la valeur est plus spécifique. Les techniques ci-dessous forment l’ensemble de travail.

Tableau de référence · 23 entrées
23 of 23 rows
Gardes intégrées
Affine les primitives : string, number, boolean, et d’autres.if (typeof x === 'string') x.toUpperCase()
Affine vers une instance de classe ou de constructible.if (e instanceof Error) e.message
Affine en vérifiant qu’une propriété existe sur la valeur.if ('id' in obj) obj.id
Affine n’importe quelle valeur en tableau ; affine une union vers son membre tableau.if (Array.isArray(x)) x.map(f)
Gardes personnalisées
Une fonction prédicat dont le retour affine l’argument.function isUser(x): x is User { return !!x.id }
Un prédicat peut affiner vers une union de types, pas seulement vers un seul.function isKey(x): x is string | number
Un prédicat d’intersection conserve le type d’entrée et lui ajoute des champs.function hasId(x): x is x & { id: string }
Une fonction d’assertion qui lève une exception si x n’est pas du type.function assertUser(x): asserts x is User
Unions discriminées
Affine une union grâce à un champ littéral partagé, via switch ou if.type E = { kind: 'a'; a: number } | { kind: 'b'; b: string }
Chaque case affine vers un membre de l’union.switch (u.kind) { case 'a': u.a }
Affine une union sans tag quand une propriété n’existe que sur un seul membre.if ('b' in u) u.b
Chaque case est une condition ; la case satisfaite affine la valeur.switch (true) { case typeof x === 'string': }
Le cas default assigne à never, prouvant que le switch est exhaustif.default: { const x: never = u }
Égalité et flux
Retire null et undefined après une vérification d’égalité.if (x === null) return; x.toFixed()
Retire les valeurs fausses (0, '', null, undefined, NaN).if (!x) return; // x is defined here
Une propriété chaînée véridique prouve que la valeur de base est présente.if (user?.active) user.name
L’assertion non-null retire null et undefined sans vérification.x!.toFixed(2)
Affectation définie : déclare que x est affecté avant d’être lu.let name!: string; init()
L’affinage s’applique dans la branche et après les retours anticipés.if (!arr) return; arr.map(...)
Alias et exécution différée
Un booléen const qui porte une vérification affine partout où il est testé.const isStr = typeof x === 'string'; if (isStr) …
Une variable const conserve son affinage dans les fermetures qui la capturent.const s = get(); if (s) use(() => s.length)
Depuis TS 5.4, un let ou un paramètre reste affiné dans les fermetures après sa dernière affectation.let n: string | null = get(); if (n) use(() => n.length)
unknown ne peut pas être utilisé tant qu’une garde ne l’a pas affiné en un type réel.if (typeof u === 'string') u.length