TypeScript satisfies : vérifier un type sans perdre la précision
Validez qu’un objet respecte un contrat tout en conservant l’inférence précise de ses propriétés, sans transformer chaque valeur en union trop large.
Où en êtes-vous avec cette notion ?
Une indication personnelle, enregistrée uniquement dans ce navigateur.
À lire ensuite
Le format café
L’essentiel à comprendre, le temps d’un café.
Envie de creuser ? Un cours plus complet vous attend juste après, à déplier sans quitter cette page.
L’idée intuitive
TypeScript sait très bien déduire le type d’une valeur. Mais parfois, vous voulez aussi vérifier qu’elle respecte un contrat précis.
Prenons une palette dont chaque couleur doit être soit une chaîne, soit un tuple RGB :
type Couleur = "rouge" | "vert" | "bleu";
type RGB = [number, number, number];
const palette = {
rouge: [255, 0, 0],
vert: "#00ff00",
bleu: [0, 0, 255],
};
TypeScript comprend naturellement que vert contient une chaîne et que rouge contient un tableau.
Le problème d’une annotation trop large
Vous pourriez imposer le contrat directement :
const palette: Record<Couleur, string | RGB> = {
rouge: [255, 0, 0],
vert: "#00ff00",
bleu: [0, 0, 255],
};
La valeur est bien vérifiée, mais palette.vert est désormais vue comme string | RGB. TypeScript ne sait plus immédiatement que cette propriété précise est une chaîne.
satisfies garde les deux avantages
satisfies signifie : « vérifie que cette expression est compatible avec ce type, mais garde son type précis ».
const palette = {
rouge: [255, 0, 0],
vert: "#00ff00",
bleu: [0, 0, 255],
} satisfies Record<Couleur, string | RGB>;
palette.vert.toUpperCase(); // OK
palette.rouge.at(0); // OK
Le contrat est contrôlé, mais l’éditeur conserve assez d’information pour savoir quelle propriété est une chaîne et laquelle est un tuple.
Et les fautes sont toujours détectées
const palette = {
rouge: [255, 0, 0],
vert: "#00ff00",
bleue: [0, 0, 255],
// ^ erreur : "bleue" n'est pas une clé attendue
} satisfies Record<Couleur, string | RGB>;
C’est particulièrement pratique pour les objets de configuration, les tables de routes, les dictionnaires et les constantes métier.
satisfies n’est pas as
as est une assertion : vous demandez à TypeScript de considérer une valeur comme un certain type. satisfies, lui, sert d’abord à vérifier la compatibilité tout en préservant l’inférence.
Et aucun des deux ne valide une donnée reçue du réseau à l’exécution : après compilation, ces informations de type disparaissent.
Fiche mémo
: Type: donne explicitement ce type à la variable.satisfies Type: vérifie la compatibilité et conserve le type précis de l’expression.as Type: affirme un type ; à utiliser quand vous savez quelque chose que TypeScript ne peut pas déduire.satisfiesagit à la compilation, jamais comme validation runtime d’une API.
L’idée à emporter : utilisez satisfies quand vous voulez dire « cet objet doit respecter ce contrat » sans sacrifier les informations précises que TypeScript avait déjà déduites.
Et si on allait plus loin ?
Le café vous a donné les repères. Prenez maintenant le temps de comprendre les mécanismes et de pratiquer, si vous le souhaitez.
Aller plus loinChoisir entre annotation, satisfies et assertion sans perdre l’inférenceDévelopper le coursReplier le cours
Ce que vous saurez faire
Utiliser satisfies sur des configurations réelles, l’associer à as const, comprendre ce qu’il ne fait pas et choisir la bonne syntaxe selon votre intention.
1. Vérifier toutes les clés d’une configuration
Supposons qu’une application possède exactement trois environnements :
type Environnement = "dev" | "staging" | "production";
type Config = {
apiUrl: string;
cache: boolean;
};
const configs = {
dev: {
apiUrl: "http://localhost:3000",
cache: false,
},
staging: {
apiUrl: "https://staging.example.com",
cache: false,
},
production: {
apiUrl: "https://example.com",
cache: true,
},
} satisfies Record<Environnement, Config>;
Le Record vérifie deux choses utiles : toutes les clés attendues existent et chaque valeur respecte Config. Une faute dans production ou une propriété cache: "oui" est signalée immédiatement.
En même temps, configs.production.cache reste connu précisément grâce à l’inférence de l’objet, au lieu de transformer toute lecture en type plus général que nécessaire.
Référence : TypeScript 4.9 — The satisfies Operator.
2. as const satisfies : figer les littéraux puis vérifier
Pour certaines constantes, vous voulez conserver les valeurs littérales exactes et empêcher leur modification :
type Route = {
path: string;
authentification: boolean;
};
type NomRoute = "accueil" | "admin";
const routes = {
accueil: { path: "/", authentification: false },
admin: { path: "/admin", authentification: true },
} as const satisfies Record<NomRoute, Route>;
Ici les deux outils ont des rôles différents :
as constrend les propriétés en lecture seule et conserve les littéraux comme"/admin"au lieu de les élargir enstring;satisfiesvérifie que l’ensemble reste compatible avec le contrat des routes.
Cette combinaison est très utile pour les configurations qui deviennent ensuite une source de types dérivés avec keyof typeof routes.
3. Le type cible n’ajoute pas de propriétés à la valeur
C’est une différence importante avec une annotation explicite.
type Options = {
tentatives: number;
timeout?: number;
};
const options = {
tentatives: 3,
} satisfies Options;
L’objet respecte bien Options, car timeout est facultatif. Mais le type précis de options reste essentiellement { tentatives: number } : satisfies ne « colle » pas artificiellement la propriété optionnelle sur la variable.
Si votre code doit manipuler la valeur comme un Options générique et accéder directement à toutes ses propriétés optionnelles, une annotation peut être plus adaptée :
const options: Options = {
tentatives: 3,
};
console.log(options.timeout); // number | undefined
Le bon choix dépend donc de l’intention : préserver une valeur précise ou travailler volontairement derrière une interface plus générale.
4. Ce n’est jamais une validation de données externes
Cette ligne est sûre pour le compilateur :
const config = {
tentatives: 3,
} satisfies Options;
Mais ceci ne devient pas sûr par magie :
const reponse = await fetch("/api/config");
const donnees = await reponse.json();
Le JSON arrive à l’exécution, après que TypeScript a fait son travail. satisfies ne peut pas vérifier le contenu réellement envoyé par le serveur. À une frontière externe, il faut une validation runtime : vérification manuelle, schéma ou bibliothèque adaptée au projet.
TypeScript supprime ses types lors de la compilation ; le JavaScript produit n’embarque donc pas le contrat Options.
5. Un tableau de décision simple
| Votre intention | Syntaxe naturelle |
|---|---|
| « Cette variable doit être manipulée comme ce type général » | const x: Type = ... |
| « Vérifie ce contrat mais garde l’inférence précise » | const x = ... satisfies Type |
| « Je connais un type que le compilateur ne peut pas établir » | valeur as Type |
| « Garde aussi les littéraux exacts et readonly » | ... as const satisfies Type |
Une assertion de type n’est pas un outil destiné à faire taire arbitrairement le compilateur. La documentation TypeScript rappelle qu’une assertion ne réalise aucun contrôle à l’exécution et qu’elle doit rester cohérente avec les types que le compilateur peut raisonnablement relier.
Référence : TypeScript Handbook — Type Assertions.
Pièges importants
- N’utilisez pas
satisfiesen espérant convertir la variable vers le type cible : son intérêt est justement de préserver son type précis. - Ne confondez pas vérification statique et validation runtime d’un JSON, d’un formulaire ou d’un fichier de configuration externe.
- Un contrat trop large comme
Record<string, unknown>vérifie peu de choses ; décrivez les clés et valeurs qui comptent réellement. - N’ajoutez pas
as constmachinalement : le readonly et les littéraux très étroits sont utiles pour des constantes, pas forcément pour des objets destinés à évoluer.
Mémo final
satisfies occupe un espace très précis dans TypeScript : contrôler une forme sans remplacer l’inférence par le type du contrat. C’est souvent exactement ce qu’il faut pour une configuration statique ou un dictionnaire dont vous voulez à la fois la sécurité et une excellente autocomplétion.
Vous pouvez aussi vous arrêter ici. L’approfondissement est facultatif.
Les repères Cours Café
Pour aller à la source
Documentation de référence. Vérification éditoriale encore à effectuer.
Gardez une trace de cette idée.
Favoris, notes et progression seront disponibles après connexion du stockage distant.