Vol. 9 · № 01 · Un atelier TypeScriptA TypeScript workshop

strict & ses drapeaux, ou chaque drapeau est un théorème strict & its flags, or each flag is a theorem

Régler le compilateur est le terrain du cargo cult : on copie un tsconfig sans savoir ce qu'il prouve. Or chaque drapeau strict active un théorème précis pour un prix précis — strictNullChecks rend l'absence explicite, noImplicitAny ferme le trou des entrées. Et strict n'active pas tout : noUncheckedIndexedAccess (arr[i] : T | undefined) reste dehors. On règle cran par cran, en comprenant — jamais en copiant, jamais tout d'un coup sur du legacy. Tuning the compiler is cargo-cult terrain: you copy a tsconfig without knowing what it proves. Yet each strict flag turns on a precise theorem for a precise price — strictNullChecks makes absence explicit, noImplicitAny shuts the input hole. And strict doesn't enable everything: noUncheckedIndexedAccess (arr[i] : T | undefined) stays outside. You tune notch by notch, understanding — never copying, never all at once on legacy.

AudienceAudience
Dev qui copie des tsconfig sans savoir quel théorème chaque drapeau active Dev who copies tsconfigs without knowing which theorem each flag enables
Format
Self-paced
ChapitresChapters
5
Date
Juin 2026 Jun 2026
≈ 18 min ●●●○ strictstrictNullChecksTradeoff
SommaireContents ·
№ 01CadrageFraming3 min

Chaque drapeau strict active un théorème. Encore faut-il savoir lequel.Each strict flag turns on a theorem. You just need to know which.

Le réglage du compilateur est le terrain le plus exposé au cargo cult : on copie un tsconfig trouvé en ligne sans savoir ce qu'il prouve. Or chaque drapeau strict active une garantie précise — un théorème que le compilateur s'engage à démontrer — pour un coût précis. Le plus fondamental, strictNullChecks : sans lui, null et undefined se glissent silencieusement dans tous les types, et un User peut être null sans que le type l'avoue. Avec lui, l'absence devient explicite, et le compilateur force à la traiter.Compiler configuration is the terrain most exposed to cargo cult: you copy a tsconfig found online without knowing what it proves. Yet each strict flag turns on a precise guarantee — a theorem the compiler commits to proving — for a precise cost. The most fundamental, strictNullChecks: without it, null and undefined silently slip into all types, and a User can be null without the type admitting it. With it, absence becomes explicit, and the compiler forces you to handle it.

Sans strictNullChecks — null se glisse partoutWithout strictNullChecks — null slips in everywhere
// strictNullChecks: false  →  null et undefined se glissent dans TOUS les types
function greet(user: User) {
  return "Bonjour " + user.name;   // user pourrait être null… le type ne le dit pas
}
greet(null);   // ✓ accepté ! 💥 null.name à l'exécution
Que prouve le drapeau ?What does the flag prove?
strictNullChecks: false
User = User ou null (caché)User = User or null (hidden)
le type ment, le crash attendthe type lies, the crash waits
strictNullChecks: true
User n'est jamais nullUser is never null
null explicite, à prouver avant usagenull explicit, prove before use

Sans le drapeau, User signifie en secret « User ou null ou undefined » — le type ne prouve rien sur la présence. Avec, User veut dire User ; l'absence se déclare (User | null) et se prouve avant usage.Without the flag, User secretly means "User or null or undefined" — the type proves nothing about presence. With it, User means User; absence is declared (User | null) and proven before use.

Avec strictNullChecks — l'absence devient expliciteWith strictNullChecks — absence becomes explicit
// strictNullChecks: true  →  null/undefined deviennent explicites
function greet(user: User) {        // User n'inclut PLUS null
  return "Bonjour " + user.name;
}
greet(null);   // ✗ Argument of type 'null' is not assignable to parameter of type 'User' — attrapé

function greetMaybe(user: User | null) {
  if (user) return "Bonjour " + user.name;   // ✓ on doit prouver la non-nullité
  return "Bonjour inconnu";
}
Le réflexe du numéroThe issue's reflex

« Le compilateur est-il réglé pour prouver, ou pour laisser passer — et est-ce que je paie le bon prix ? » On ne touche à un drapeau qu'en comprenant le théorème qu'il active ou désactive, jamais en copiant un tsconfig trouvé en ligne."Is the compiler tuned to prove, or to let through — and am I paying the right price?" You only touch a flag by understanding the theorem it enables or disables, never by copying a tsconfig found online.

Le dernier volume, et pourquoi maintenant.The last volume, and why now.

On garde le réglage du compilateur pour la fin — pas le début — exprès. Régler strict avant de comprendre l'effacement, le narrowing, any, les frontières, c'est cargo-culter. Maintenant qu'on a les théorèmes en tête, on peut décider lesquels activer en connaissance de cause. Beaucoup de ces drapeaux, on les a déjà croisés.We keep compiler config for the end — not the start — on purpose. Tuning strict before grasping erasure, narrowing, any, boundaries is cargo-culting. Now that the theorems are in mind, we can decide which to enable knowingly. Many of these flags we've already met.

№ 02La surpriseThe surprise4 min

Même en strict, arr[i] est typé T — alors qu'il peut être undefined.Even in strict, arr[i] is typed T — though it can be undefined.

La surprise que presque tout le monde rate : strict n'inclut pas noUncheckedIndexedAccess. Par défaut, donc, xs[10] est typé number même si l'indice est hors limites, et cfg["absent"] est typé string même si la clé n'existe pas. Le compilateur ne peut pas prouver qu'un indice est valide — mais il fait comme si. Le drapeau noUncheckedIndexedAccess corrige ce mensonge : tout accès indexé devient T | undefined, et l'on doit prouver la présence. C'est le drapeau le plus sous-utilisé, et l'un des plus honnêtes.The surprise almost everyone misses: strict does not include noUncheckedIndexedAccess. By default, then, xs[10] is typed number even out of bounds, and cfg["absent"] is typed string even if the key doesn't exist. The compiler can't prove an index is valid — but it pretends to. The noUncheckedIndexedAccess flag fixes this lie: every indexed access becomes T | undefined, and you must prove presence. It's the most underused flag, and one of the most honest.

L'accès indexé prétend toujours réussirIndexed access always pretends to succeed
// noUncheckedIndexedAccess: false (le défaut, même en strict)
const xs: number[] = [1, 2, 3];
const x = xs[10];        // x : number — alors que xs[10] est undefined !
x.toFixed();             // 💥 aucune erreur, mais undefined.toFixed à l'exécution

const cfg: Record<string, string> = {};
cfg["absent"].trim();    // 💥 même mensonge : type string, valeur undefined

Hors limites ou clé absente, le type reste number / string : le compilateur affirme une présence qu'il n'a pas prouvée. C'est un mensonge structurel toléré par défaut, même sous strict — et une source classique de undefined is not a function.Out of bounds or missing key, the type stays number / string: the compiler asserts a presence it never proved. It's a structural lie tolerated by default, even under strict — and a classic source of undefined is not a function.

strict n'est pas « tout activé ». Le drapeau le plus honnête sur les accès indexés n'en fait même pas partie — il faut le demander, en sachant ce qu'il prouve.strict isn't "everything on". The most honest flag about indexed access isn't even part of it — you must ask for it, knowing what it proves.
№ 03La mécaniqueThe mechanics5 min

strict est un parapluie — et plusieurs de ses drapeaux, on les a déjà rencontrés.strict is an umbrella — and several of its flags we've already met.

strict: true n'est pas un drapeau, c'est un parapluie qui en active une famille. La plupart ont déjà traversé cette série : noImplicitAny attrape les any implicites des entrées (Vol 4.1), strictFunctionTypes rend les paramètres de fonction contravariants (Vol 5.3), useUnknownInCatchVariables type le catch en unknown (Vol 8.2), strictNullChecks rend l'absence explicite (chapitre 1). Mais deux théorèmes utiles restent hors parapluie : noUncheckedIndexedAccess et exactOptionalPropertyTypes. Connaître la liste, c'est savoir ce qu'on prouve — et ce qu'on a oublié d'activer.strict: true isn't a flag, it's an umbrella that turns on a family. Most have already crossed this series: noImplicitAny catches input implicit anys (Vol 4.1), strictFunctionTypes makes function parameters contravariant (Vol 5.3), useUnknownInCatchVariables types catch as unknown (Vol 8.2), strictNullChecks makes absence explicit (chapter 1). But two useful theorems stay outside the umbrella: noUncheckedIndexedAccess and exactOptionalPropertyTypes. Knowing the list means knowing what you prove — and what you forgot to enable.

Sous le parapluie strict — des théorèmes déjà vusUnder the strict umbrella — theorems already seen
// "strict": true active d'un coup, entre autres :
{
  "strictNullChecks": true,          // null/undefined explicites      (ch. 1)
  "noImplicitAny": true,             // les any implicites = erreur     (Vol 4.1)
  "strictFunctionTypes": true,       // params de fonction contravariants (Vol 5.3)
  "useUnknownInCatchVariables": true // catch (e) : unknown             (Vol 8.2)
}
// mais PAS noUncheckedIndexedAccess ni exactOptionalPropertyTypes — à activer en plus
// (depuis TS 6.0, strict est activé par défaut ; l'écrire reste le plus clair)
Hors parapluie — à activer en connaissance de causeOutside the umbrella — enable knowingly
// Hors du parapluie strict — à demander explicitement :
{
  "noUncheckedIndexedAccess": true,    // arr[i] : T | undefined          (ch. 2)
  "exactOptionalPropertyTypes": true   // { x?: number } refuse x: undefined
}
Le drapeau, le théorème, le prixThe flag, the theorem, the price
Le théorèmeThe theorem
strictNullChecksl'absence est expliciteabsence is explicit
noImplicitAnypas de any caché (4.1)no hidden any (4.1)
noUncheckedIndexedAccessl'accès indexé peut manquerindexed access may miss
Le prixThe price
gardesguardsvérifier null avant usagecheck null before use
annotationsannotationstyper ce qui était implicitetype what was implicit
verbositéverbosityprouver chaque accèsprove each access
Les voisins, seulement nommés.The neighbors, only named.

exactOptionalPropertyTypes distingue « propriété absente » de « propriété présente valant undefined » — un { x?: number } n'accepte plus { x: undefined }. Pour migrer un projet existant, on n'active pas tout d'un coup : on peut passer en strict dossier par dossier — un tsconfig par zone, reliées par des project references —, et marquer les erreurs restantes d'un // @ts-expect-error à résorber. (Aucune option de tsconfig ne le fait fichier par fichier.) Et l'on retrouvera ces drapeaux dans le coût de compilation (9.2) : prouver plus, c'est aussi typer plus longtemps.exactOptionalPropertyTypes distinguishes "property absent" from "property present and equal to undefined" — a { x?: number } no longer accepts { x: undefined }. To migrate an existing project, you don't enable everything at once: you can go strict folder by folder — one tsconfig per area, linked by project references — and mark the remaining errors with a // @ts-expect-error to burn down. (No tsconfig option does it file by file.) And you'll meet these flags again in compile cost (9.2): proving more also means typechecking longer.

№ 04Le piègeThe trap4 min

Copier un tsconfig et tout activer d'un coup — puis tout désactiver, vaincu.Copy a tsconfig and enable it all at once — then disable it all, defeated.

Le contre-exemple du volume : prendre une config trouvée en ligne, activer tous les drapeaux d'un coup sur un projet existant, voir des milliers d'erreurs, paniquer, et tout remettre à false. On en ressort avec moins de garanties qu'avant, et la conviction tenace que strict est inadapté. C'est l'inverse de la règle : on ne touche un drapeau qu'en comprenant son théorème, et l'on migre progressivement — le socle d'abord, puis un drapeau à la fois, chacun avec ses erreurs traitées avant de passer au suivant.The volume's counter-example: take a config found online, enable every flag at once on an existing project, see thousands of errors, panic, and set it all back to false. You come out with fewer guarantees than before, and the stubborn belief that strict is unsuited. It's the opposite of the rule: you touch a flag only by understanding its theorem, and you migrate progressively — the base first, then one flag at a time, each with its errors handled before moving on.

Le mur d'erreurs qui fait tout abandonnerThe wall of errors that makes you give up
// Repris d'un gist, collé tel quel sur un projet legacy :
{
  "strict": true,
  "noUncheckedIndexedAccess": true,
  "exactOptionalPropertyTypes": true
}
// 4 800 erreurs au premier tsc. On panique, on remet "strict": false.
// Résultat : zéro garantie, et la conviction que strict "ne marche pas ici".

Tout activer sur du code non préparé, c'est se noyer sous des erreurs qu'on n'a pas le temps de traiter — et le réflexe de survie est de tout couper. On se retrouve sans aucune garantie, en croyant que c'est strict le problème. Le cargo cult ne punit pas l'ignorance : il la fige.Enabling everything on unprepared code is drowning under errors you have no time to handle — and the survival reflex is to cut it all. You end up with no guarantee at all, believing strict is the problem. Cargo cult doesn't punish ignorance: it freezes it.

L'inverse est un piège aussi.The opposite is a trap too.

Laisser strict à false « pour aller vite » désactive en bloc les théorèmes sur lesquels reposent tout le reste : sans strictNullChecks, le null ment (ch. 1) ; sans noImplicitAny, le trou du Vol 4 est rouvert ; sans useUnknownInCatchVariables, l'erreur du Vol 8.2 est non typée. Le bon réglage n'est ni « tout, tout de suite » ni « rien » — c'est « le plus possible, compris, au rythme où le code peut suivre ».Leaving strict at false "to go fast" disables wholesale the theorems everything else rests on: without strictNullChecks, null lies (ch. 1); without noImplicitAny, Vol 4's hole reopens; without useUnknownInCatchVariables, Vol 8.2's error is untyped. The right setting is neither "everything, now" nor "nothing" — it's "as much as possible, understood, at the pace the code can follow".

Un drapeau qu'on active sans comprendre son théorème ne protège pas — il s'éteint au premier mur d'erreurs. La config se justifie cran par cran, ou elle ne tient pas.A flag enabled without understanding its theorem doesn't protect — it switches off at the first wall of errors. Config is justified notch by notch, or it doesn't hold.
№ 05Bilan & éditoWrap-up & editorial2 min

Chaque drapeau est un théorème — à activer en le comprenant, pas en le copiant.Each flag is a theorem — to enable by understanding it, not by copying it.

strict est un parapluie de drapeaux, chacun activant une garantie précise pour un prix précis : strictNullChecks rend l'absence explicite, noImplicitAny ferme le trou des entrées, et plusieurs autres qu'on a déjà croisés. Deux théorèmes utiles restent dehors : noUncheckedIndexedAccess et exactOptionalPropertyTypes. Le bon réglage se décide cran par cran, en comprenant ce que chacun prouve — jamais en copiant un tsconfig, jamais en activant tout d'un bloc sur du code non prêt.strict is an umbrella of flags, each turning on a precise guarantee for a precise price: strictNullChecks makes absence explicit, noImplicitAny shuts the input hole, and several others already met. Two useful theorems stay outside: noUncheckedIndexedAccess and exactOptionalPropertyTypes. The right setting is decided notch by notch, understanding what each proves — never by copying a tsconfig, never by enabling everything at once on unready code.

Tu veux prouver…You want to prove…Le drapeauThe flagCe que ça coûteWhat it costs
Que l'absence est géréeThat absence is handledstrictNullChecks — null/undefined explicites.strictNullChecks — null/undefined explicit.Des gardes à écrire avant chaque accès risqué.Guards to write before each risky access.
Qu'un accès indexé peut manquerThat an indexed access may missnoUncheckedIndexedAccess (hors strict).noUncheckedIndexedAccess (outside strict).arr[i] devient T | undefined — plus de gardes.arr[i] becomes T | undefined — more guards.
Le socle d'un coupThe base at once"strict": true — le parapluie."strict": true — the umbrella.Inclut beaucoup, mais pas tout — connaître la liste.Includes much, not all — know the list.
Ne PAS faireNOT doCopier un tsconfig, tout activer sur du legacy.Copy a tsconfig, enable all on legacy.Mur d'erreurs → on désactive → zéro garantie.Wall of errors → you disable → zero guarantee.
Un drapeau n'est pas un interrupteur de confort — c'est un théorème que tu demandes au compilateur de démontrer, et dont tu paies la preuve.A flag isn't a comfort switch — it's a theorem you ask the compiler to prove, and whose proof you pay for.
Mot de l'éditeurFrom the editor

« Réglé pour prouver, ou pour laisser passer ? »"Tuned to prove, or to let through?"

On garde le réglage du compilateur pour la fin, et ce n'est pas un hasard. Toucher à strict avant d'avoir compris l'effacement, le narrowing, la propagation d'any, l'inconnu de la frontière, c'est exactement le cargo cult que la série combat : copier des incantations qui « font passer », sans savoir ce qu'elles prouvent. Maintenant, chaque drapeau a un nom et un théorème : strictNullChecks rend l'absence visible, noImplicitAny ferme le trou des entrées, noUncheckedIndexedAccess avoue qu'un accès peut rater. On ne les active plus par foi, mais parce qu'on sait quelle preuve on achète, et à quel prix.We keep compiler config for the end, and that's no accident. Touching strict before grasping erasure, narrowing, any propagation, the boundary's unknown, is exactly the cargo cult the series fights: copying incantations that 'make it pass', without knowing what they prove. Now, each flag has a name and a theorem: strictNullChecks makes absence visible, noImplicitAny shuts the input hole, noUncheckedIndexedAccess admits an access can miss. You no longer enable them on faith, but because you know which proof you buy, and at what price.

Mais prouver coûte, et pas seulement en gardes à écrire : prouver coûte aussi en temps. Plus on demande au compilateur de vérifier — et plus les types qu'on lui donne sont alambiqués —, plus tsc et l'éditeur ralentissent. Le prochain numéro mesure ce prix-là : le coût de compilation des types trop intelligents, et le moment où la prouesse au niveau type se paie en secondes d'attente à chaque frappe. Régler le compilateur, c'est arbitrer entre ce qu'on prouve et ce qu'on attend.But proving costs, and not only in guards to write: proving also costs time. The more you ask the compiler to check — and the more convoluted the types you give it — the more tsc and the editor slow down. The next issue measures that price: the compile cost of too-clever types, and the moment type-level feats are paid in seconds of waiting at every keystroke. Tuning the compiler is arbitrating between what you prove and what you wait for.