Vol. 7 · № 03 · Un atelier TypeScriptA TypeScript workshop

satisfies, ou vérifier sans élargir satisfies, or check without widening

Pour une valeur qu'on écrit : l'annotation vérifie mais élargit (on perd les clés exactes), le as force et peut mentir. satisfies fait les deux bons gestes — il vérifie la conformité ET garde le type précis inféré. Là où tu mettais un as pour « faire respecter » une forme, tu voulais satisfies : contrôler, pas forcer. Sa portée : les valeurs que tu rédiges, pas la donnée du dehors (ça, c'est parse). For a value you write: the annotation checks but widens (you lose the exact keys), as forces and can lie. satisfies does both right things — it checks conformance AND keeps the precise inferred type. Where you put an as to 'enforce' a shape, you meant satisfies: check, don't force. Its scope: values you author, not outside data (that's parse).

AudienceAudience
Dev qui dégaine as pour « faire respecter » une forme sur ses propres objets Dev who reaches for as to 'enforce' a shape on their own objects
Format
Self-paced
ChapitresChapters
5
Date
Juin 2026 Jun 2026
≈ 18 min ●●●○ satisfiesInférenceTradeoff
SommaireContents ·
№ 01CadrageFraming3 min

L'annotation vérifie mais élargit. Le as garde mais ne vérifie pas.The annotation checks but widens. The as keeps but doesn't check.

Pour une valeur qu'on écrit soi-même — un objet de config, une palette, une table de routes — on veut deux choses : qu'elle respecte une forme attendue, et qu'on garde le type précis que TypeScript infère (les clés exactes, le type fin de chaque propriété). L'annotation donne la vérification mais élargit tout vers le type déclaré. Le as garde la forme mais ne vérifie rien et peut mentir. On est coincé entre sûreté-sans-précision et précision-sans-sûreté — jusqu'à satisfies, épaulé d'un as const quand on veut aussi figer les littéraux.For a value you write yourself — a config object, a palette, a route table — you want two things: that it respects an expected shape, and that you keep the precise type TypeScript infers (the exact keys, each property's narrow type). The annotation gives the check but widens everything to the declared type. The as keeps the shape but checks nothing and can lie. You're stuck between safety-without-precision and precision-without-safety — until satisfies, backed by as const when you also want the literals frozen.

Le dilemme — l'annotation élargit, le as mentThe dilemma — the annotation widens, the as lies
// annotation : vérifie, mais ÉLARGIT — clés exactes et littéraux perdus
const routes: Record<string, string> = { home: "/", admin: "/admin" };
routes.home;   // string (pas "/") — précision perdue
routes.typo;   // string — aucune erreur sur une clé inventée !

// as : garde la forme voulue, mais NE VÉRIFIE PAS
const r2 = { home: "/" } as Record<"home" | "admin", string>;  // admin manque — passe quand même
Vérifie ? Garde le type précis ?Checks? Keeps the precise type?
: T
vérifie ✓checks ✓
élargit vers T ✗widens to T ✗
as T
ne vérifie pas ✗no check ✗
force T (peut mentir)forces T (can lie)
satisfies T
vérifie ✓checks ✓
garde le type précis ✓keeps precise type ✓

satisfies fait ce qu'aucun des deux ne sait : il contrôle la conformité (comme l'annotation) tout en conservant le type le plus précis (comme l'inférence nue) — sans rien forcer ni élargir.satisfies does what neither can: it checks conformance (like the annotation) while keeping the most precise type (like bare inference) — forcing and widening nothing.

as const satisfies — vérifie ET garde la précisionas const satisfies — checks AND keeps precision
// as const (Vol 4.3) fige les littéraux ; satisfies vérifie la forme
const routes = { home: "/", admin: "/admin" } as const satisfies Record<string, string>;

routes.home;   // "/"  — littéral conservé (par as const)
routes.typo;   // ✗ 'typo' n'existe pas — satisfies a gardé les clés exactes
// et une clé manquante, ou { admin: 42 }, serait refusée : la conformité EST vérifiée
Le réflexe du numéroThe issue's reflex

« Je veux contrôler sans perdre la précision → satisfies, pas as. » Là où l'on dégainait un as pour « faire respecter » une forme, on voulait presque toujours vérifier, pas forcer."I want to check without losing precision → satisfies, not as." Where you reached for an as to "enforce" a shape, you almost always meant to verify, not force.

Pourquoi ce numéro clôt le Vol 7.Why this issue closes Vol 7.

La frontière ment (7.1) ; on parse la donnée reçue (7.2) ; et pour les valeurs qu'on écrit soi-même, satisfies remplace le as par une vérification qui garde la précision (7.3). Les deux derniers numéros se répartissent le travail : parse pour ce qui entre, satisfies pour ce qu'on rédige. Et satisfies referme la question du as ouverte au Vol 4.The boundary lies (7.1); you parse received data (7.2); and for the values you write yourself, satisfies replaces as with a check that keeps precision (7.3). The last two issues split the work: parse for what comes in, satisfies for what you author. And satisfies closes the as question opened in Vol 4.

№ 02La surpriseThe surprise4 min

Ils se ressemblent — mais as force, et satisfies vérifie.They look alike — but as forces, and satisfies checks.

Les deux se posent après une valeur, suivis d'un type — on les croit interchangeables. Ils sont opposés. as est une assertion : il déclare un type sans le vérifier, et si l'on s'est trompé, le bug revient au runtime (Vol 4.3). satisfies est un contrôle : il exige que la valeur soit assignable au type, refuse sinon, et — c'est là le cadeau — laisse intact le type précis que TypeScript a inféré. Même syntaxe de surface, sécurité inverse.Both sit after a value, followed by a type — you think them interchangeable. They're opposites. as is an assertion: it declares a type without checking it, and if you got it wrong, the bug returns at runtime (Vol 4.3). satisfies is a check: it requires the value to be assignable to the type, refuses otherwise, and — here's the gift — leaves intact the precise type TypeScript inferred. Same surface syntax, opposite safety.

as accepte une valeur fausse — et le crash suitas accepts a wrong value — and the crash follows
const config = {
  host: "localhost",     // ✗ port oublié…
} as { host: string; port: number };   // …mais 'as' FORCE le type — aucune erreur

config.port.toFixed();   // 💥 port est undefined : as a menti, crash au runtime

as dit au compilateur « c'est un { host: string; port: number } », et il le croit — alors que port n'existe pas. Aucune erreur, le mensonge passe, et .toFixed() explose à l'exécution. C'est l'assertion du Vol 4 : forcer, pas prouver. (as ne refuse que l'absurde flagrant — un string vers un number déclenche TS2352 ; tout ce qui pourrait coller, comme une propriété manquante, passe.)as tells the compiler "this is a { host: string; port: number }", and it believes it — even though port doesn't exist. No error, the lie passes, and .toFixed() blows up at runtime. It's the Vol 4 assertion: force, don't prove. (as only refuses the blatantly absurd — a string to a number triggers TS2352; anything that could fit, like a missing property, goes through.)

as dit au compilateur « crois-moi » ; satisfies lui dit « vérifie-moi ». La même position, deux verbes opposés — l'un force, l'autre prouve.as tells the compiler "trust me"; satisfies tells it "check me". The same position, two opposite verbs — one forces, the other proves.
№ 03La mécaniqueThe mechanics5 min

Trois outils, une valeur : seul satisfies vérifie et rend le type de la valeur.Three tools, one value: only satisfies checks and returns the value's type.

La mécanique tient à une question : que devient le type de l'expression ? L'annotation et le as donnent tous deux le type déclaré T — l'un en vérifiant, l'autre en forçant. satisfies fait autrement : il vérifie l'assignabilité de la valeur à T, puis donne à l'expression le type de la valeur elle-même, pas T. C'est un contrôle qui rend son entrée inchangée. D'où la conservation des clés exactes et du type fin de chaque propriété : la valeur n'a jamais été remplacée par T. Les littéraux, eux, s'élargissent comme dans toute inférence — c'est as const qui les fige, pas satisfies.The mechanic comes down to one question: what does the expression's type become? Both annotation and as give the declared type T — one by checking, the other by forcing. satisfies does otherwise: it checks the value's assignability to T, then gives the expression the value's own type, not T. It's a check that returns its input unchanged. Hence the preservation of exact keys and each property's narrow type: the value was never replaced by T. Literals, though, widen as in any inference — as const freezes them, not satisfies.

La même valeur, trois types de sortieThe same value, three output types
const v = { home: "/", admin: "/admin" };

const a: Record<string, string> = v;          // annotation → type : Record<string,string>
const b = v as Record<string, string>;         // assertion  → type : Record<string,string>
const c = v satisfies Record<string, string>;  // satisfies  → type : { home: string; admin: string }
//                                                 ↑ seul satisfies garde les clés exactes : c.typo ✗
La règle : qui vérifie, quel type en sortThe rule: who checks, which type comes out
// La règle, en une phrase :
//   satisfies VÉRIFIE que v est assignable à T (sinon : erreur),
//   puis donne à l'expression le type de v — PAS celui de T.
//
//   annotation : v assignable à T ?  →  type = T        (élargi)
//   as         : (aucune vérif)      →  type = T        (forcé)
//   satisfies  : v assignable à T ?  →  type = typeof v  (préservé)
Les trois outils, côte à côteThe three tools, side by side
Vérifie ?Checks?
: Toui (puis élargit)yes (then widens)
as Tnon (force, peut mentir)no (forces, can lie)
satisfies Toui (et garde le type)yes (and keeps the type)
Type obtenuResulting type
: TT
as TT
satisfies Tle type de la valeurthe value's type
Les voisins, seulement nommés.The neighbors, only named.

On combine souvent satisfies avec as const (Vol 4.3) : as const fige les littéraux et le readonly, satisfies vérifie la forme — sans rien forcer. Et tout cela s'efface à l'exécution (Vol 2) : satisfies est un contrôle de compilation sur une valeur que tu écris — il ne valide aucune donnée reçue (ça, c'est parse, le 7.2).You often combine satisfies with as const (Vol 4.3): as const freezes literals and readonly, satisfies checks the shape — forcing nothing. And all of it erases at runtime (Vol 2): satisfies is a compile-time check on a value you write — it validates no received data (that's parse, the 7.2).

№ 04Le piègeThe trap4 min

Le as mis pour « faire respecter » une forme — là où satisfies la vérifie vraiment.The as used to "enforce" a shape — where satisfies actually checks it.

Le contre-exemple obligatoire : poser un as sur un objet qu'on écrit, en croyant lui « imposer » une forme. Mais as n'impose rien — il affirme, sans vérifier, et laisse passer une valeur du mauvais type. C'est exactement l'emploi que satisfies remplace : on voulait contrôler, on a forcé. Deux nuances closent le sujet : satisfies n'est pas toujours le bon choix, et il ne touche jamais aux données du dehors.The mandatory counter-example: putting an as on an object you write, thinking you 'impose' a shape on it. But as imposes nothing — it asserts, without checking, and lets a wrong-typed value through. It's exactly the use satisfies replaces: you meant to check, you forced. Two nuances close the topic: satisfies isn't always the right choice, and it never touches outside data.

as laisse passer la valeur du mauvais typeas lets the wrong-typed value through
// "Forcer" la conformité d'un objet de thème avec as :
type Theme = Record<"primary" | "spacing", string | number>;
const theme = {
  primary: "#0a0a0a",
} as Theme;   // ✗ spacing oublié — mais as ne dit rien

theme.spacing.toString();   // 💥 undefined.toString : as a forcé un mensonge

On a posé as pour « garantir » que le thème a ses deux clés — mais spacing manque, et as n'a rien vu. « Imposer » avec as est une illusion : il déclare, il ne contrôle pas. Le crash attend .toString().You put as to "guarantee" the theme has both its keys — but spacing is missing, and as saw nothing. "Enforcing" with as is an illusion: it declares, it doesn't check. The crash waits at .toString().

Deux limites à connaître.Two limits to know.

(1) satisfies garde le type précis — ce n'est pas toujours voulu : pour un contrat public ou une variable réassignable, on veut le type large déclaré, donc l'annotation : T. (2) satisfies s'efface (Vol 2) et ne contrôle que des valeurs que tu écris ; sur du any venu d'un JSON.parse, data satisfies User ne vérifie rien (un any est assignable à tout). Pour la donnée du dehors : parse (7.2), jamais satisfies.(1) satisfies keeps the precise type — not always wanted: for a public contract or a reassignable variable, you want the wide declared type, so the annotation : T. (2) satisfies erases (Vol 2) and only checks values you write; on any from a JSON.parse, data satisfies User checks nothing (an any is assignable to everything). For outside data: parse (7.2), never satisfies.

Si tu écris as pour vérifier une valeur que tu rédiges, tu voulais satisfies. as ordonne ; satisfies contrôle — et seul le second peut dire non.If you write as to check a value you author, you meant satisfies. as orders; satisfies checks — and only the second can say no.
№ 05Bilan & éditoWrap-up & editorial2 min

Vérifier sans élargir — le contrôle que le as faisait semblant d'être.Check without widening — the verification the as only pretended to be.

satisfies sépare deux choses que le as confondait : contrôler une conformité, et choisir le type qui en résulte. L'annotation vérifie mais élargit ; le as force et peut mentir ; satisfies vérifie ET garde le type précis inféré. Là où tu mettais un as pour faire respecter une forme, tu voulais satisfies. Sa portée : les valeurs que tu écris, à la compilation — pas la donnée du dehors, qui se parse (7.2).satisfies separates two things as conflated: checking conformance, and choosing the resulting type. The annotation checks but widens; as forces and can lie; satisfies checks AND keeps the precise inferred type. Where you put an as to enforce a shape, you meant satisfies. Its scope: values you write, at compile time — not outside data, which is parsed (7.2).

Tu veux…You want to…Le gesteThe moveCe que ça coûteWhat it costs
Vérifier qu'une valeur respecte un typeCheck a value respects a typevaleur satisfies T.value satisfies T.Vérifie sans élargir — garde le type précis.Checks without widening — keeps the precise type.
Garder les clés et types exacts d'un configKeep a config's exact keys and typessatisfies (pas l'annotation : T) ; ajoute as const pour figer aussi les littéraux.satisfies (not the annotation : T); add as const to also freeze the literals.L'annotation élargit et perd les clés exactes.The annotation widens and loses the exact keys.
Remplacer un as « de conformité »Replace a 'conformance' asSouvent satisfies : il vérifie au lieu de forcer.Often satisfies: it checks instead of forcing.as peut mentir ; satisfies refuse le non-conforme.as can lie; satisfies refuses the non-conforming.
Ne PAS l'employerNOT use itSur une donnée du dehors (any), ou un contrat public.On outside data (any), or a public contract.satisfies s'efface (Vol 2) ; pour le bord, parse.satisfies erases (Vol 2); for the edge, parse.
L'annotation te donne T, le as te donne T sans garantie. satisfies te rend ta valeur, prouvée conforme — vérifiée, et intacte.The annotation gives you T, the as gives you T with no guarantee. satisfies hands your value back, proven conforming — checked, and intact.
Mot de l'éditeurFrom the editor

« Vérifier sans élargir. »"Check without widening."

Pendant des années, on n'avait que deux gestes pour confronter une valeur à un type, et chacun sacrifiait quelque chose. L'annotation vérifiait, mais remplaçait le type précis par le type déclaré : on perdait les clés exactes, et l'on pouvait soudain lire des clés qui n'existaient pas. Le as gardait la main sur le type, mais ne vérifiait rien — il forçait, et pouvait mentir. satisfies est la pièce manquante : il contrôle la conformité comme l'annotation, et conserve le type inféré comme l'inférence nue. Un contrôle qui rend son entrée inchangée. La confusion la plus utile à dissiper de tout le volume : là où le réflexe disait as, il fallait presque toujours satisfies — vérifier, pas forcer.For years, you had only two moves to confront a value with a type, and each sacrificed something. The annotation checked, but replaced the precise type with the declared one: you lost the exact keys, and could suddenly read keys that didn't exist. The as kept control of the type, but checked nothing — it forced, and could lie. satisfies is the missing piece: it checks conformance like the annotation, and keeps the inferred type like bare inference. A check that returns its input unchanged. The most useful confusion to clear in the whole volume: where the reflex said as, you almost always needed satisfies — check, don't force.

Mais il faut tenir les deux ensemble. satisfies s'efface à l'exécution (Vol 2) : il ne contrôle que des valeurs que tu écris toi-même, jamais une donnée reçue — pour celle-là, c'est parse (7.2), jamais satisfies sur un any. Ainsi se boucle le Vol 7 : la frontière ment, on parse ce qui entre, on vérifie ce qu'on rédige. Reste une dernière région où les types promettent moins qu'on ne croit — l'asynchrone. Un Promise<T> type la valeur de succès, et passe entièrement sous silence l'erreur. C'est le prochain volume : ce que await garantit, et ce qu'il ne dira jamais.But you must hold both together. satisfies erases at runtime (Vol 2): it only checks values you write yourself, never received data — for that, it's parse (7.2), never satisfies on an any. So Vol 7 closes the loop: the boundary lies, you parse what comes in, you check what you author. One last region remains where types promise less than you think — the asynchronous. A Promise<T> types the success value, and stays entirely silent on the error. That's the next volume: what await guarantees, and what it will never tell you.