Une réponse d'API est soit une facture, soit un message d'erreur. Un statut vaut « brouillon », « envoyée » ou « payée », et rien d'autre.
Le type union sert à écrire exactement cela, puis à obliger le code à traiter chaque cas.
Définition
Un type union énumère les types qu'une valeur est autorisée à prendre, séparés par une barre verticale. La valeur en vaut un seul à la fois, et le compilateur refuse tout ce qui ne figure pas dans la liste.
type Statut = "brouillon" | "envoyee" | "payee";
let statutFacture: Statut = "payee";
statutFacture = "annulee";
// Type '"annulee"' is not assignable to type 'Statut'.
type Identifiant = string | number;Les trois valeurs de Statut ne sont pas des types au sens habituel : ce sont des types littéraux, chacun n'acceptant qu'une seule chaîne. C'est ce qui remplace avantageusement une constante d'énumération maison.
Le rétrécissement
Tant que la valeur est une union, seules les propriétés communes à tous les membres sont accessibles. Un test suffit à réduire l'ensemble, et le compilateur suit le raisonnement branche par branche.
function taille(valeur: string | number): number {
if (typeof valeur === "string") {
return valeur.length; // ici, valeur est une chaîne
}
return valeur; // ici, c'est forcément un nombre
}Trois opérateurs servent à ce rétrécissement : typeof pour les types primitifs, instanceof pour les classes, et in pour tester la présence d'une propriété. Une Égalité stricte (===) sur un type littéral fonctionne aussi.
L'union discriminée
Le cas le plus utile en pratique : chaque membre porte un champ commun dont la valeur l'identifie. Tester ce champ suffit alors à débloquer les autres propriétés du membre.
type ReponseApi =
| { ok: true; facture: { id: number } }
| { ok: false; erreur: string };
function afficher(reponse: ReponseApi) {
if (reponse.ok) {
console.log(reponse.facture.id);
} else {
console.log(reponse.erreur);
}
}Lire reponse.facture avant le test est refusé : la propriété n'existe pas sur le membre d'échec. L'union rend impossible l'oubli qui, en JavaScript, produit un undefined silencieux.
Questions fréquentes
Quelle différence avec une intersection ?
L'union se note avec une barre verticale et signifie « l'un ou l'autre » ; l'intersection se note avec une esperluette et signifie « les deux à la fois ». La première réduit ce qui est accessible, la seconde l'augmente. On les confond souvent au début, parce que « ou » donne intuitivement l'impression d'élargir.
Comment être certain de traiter tous les cas ?
Un switch sur le champ discriminant, sans branche default, avec un type de retour annoté : si un membre est oublié, le compilateur signale qu'un chemin ne rend rien. C'est le contrôle d'exhaustivité, et il se rappelle à vous le jour où un quatrième statut est ajouté.
Une union peut-elle contenir null ?
Oui, et c'est même son usage le plus courant en mode strict : string | null décrit une valeur qui peut manquer, et le compilateur exige un test avant toute lecture. La Coalescence des nuls (??) et le Chaînage optionnel (?.) deviennent alors les deux outils qui allègent ces tests.