Journal

Maîtriser `satisfies`, les types littéraux et les unions discriminées

Journal du mercredi 26 août 2026, généré le 26 août à 21:44

L'opérateur satisfies : le meilleur des deux mondes

Beaucoup de développeurs annotent encore leurs objets de configuration avec un type explicite, au prix d'une perte d'inférence précise. L'opérateur satisfies, disponible depuis TypeScript 4.9, vérifie la conformité d'une valeur à un type sans élargir son type inféré.

type Couleur = "red" | "green" | "blue";

const palette = {
  primaire: "red",
  secondaire: "blue"
} satisfies Record<string, Couleur>;

// palette.primaire est inféré comme "red", pas comme Couleur
palette.primaire.toUpperCase();

Avec une annotation classique (: Record<string, Couleur>), TypeScript aurait élargi chaque propriété au type Couleur, perdant l'information que primaire vaut précisément "red". satisfies conserve cette précision tout en garantissant l'erreur si une valeur ne respecte pas la contrainte.

Unions discriminées et narrowing exhaustif

Les unions discriminées restent la façon la plus robuste de modéliser des états mutuellement exclusifs. Combinées à une fonction utilitaire assertNever, elles rendent le compilateur capable de détecter les cas oubliés.

type Etat =
  | { statut: "chargement" }
  | { statut: "succes"; donnees: string[] }
  | { statut: "erreur"; message: string };

function assertNever(x: never): never {
  throw new Error("Cas non gere: " + JSON.stringify(x));
}

function afficher(e: Etat): string {
  switch (e.statut) {
    case "chargement": return "...";
    case "succes": return e.donnees.join(", ");
    case "erreur": return e.message;
    default: return assertNever(e);
  }
}

Si un nouveau statut est ajouté à l'union sans être traité dans le switch, la branche default ne compile plus : l'erreur remonte immédiatement, avant même l'exécution.

Types littéraux de gabarit (template literal types)

Les template literal types permettent de construire des types chaînes à partir de motifs, utiles pour typer des routes, des noms d'événements ou des variables CSS.

type Ressource = "user" | "post" | "comment";
type Route = `/api/${Ressource}/${number}`;

const r: Route = "/api/post/42"; // valide

Points de vigilance

  • satisfies ne remplace pas les annotations de fonctions publiques : il est surtout pertinent pour les valeurs littérales internes.
  • Préférez const assertions (as const) en complément de satisfies quand vous voulez aussi figer les tableaux et littéraux en lecture seule.
  • L'exhaustivité via never ne fonctionne que si le compilateur peut réellement réduire l'union à zéro membre : évitez les any qui cassent la chaîne d'inférence.