Le bug que JavaScript ne voit pas
Tu connais ce bug. Tout le monde connaît ce bug. Une fonction JavaScript qui, dans un cas sur dix, oublie de renvoyer quelque chose. Le code tourne, aucune erreur, et trois fonctions plus loin un calcul affiche NaN ou la page plante sur Cannot read properties of undefined, à 2h du matin, chez un utilisateur, jamais chez toi.
function appliquerCoupon(total, code) {
if (code === 'PROMO10') {
return total - total * 0.10;
}
// …et si le code promo est vide ? La fonction renvoie undefined.
}
const aPayer = appliquerCoupon(100, '');
console.log(aPayer * 1.2); // NaN : bonne chance pour le retrouver
JavaScript ne dira jamais rien sur ce code : il est syntaxiquement parfait. L'erreur n'existera qu'à l'exécution, sur le chemin précis que personne n'a testé à la main. Et si ce code a été généré par une IA, tu l'as peut-être validé en trois secondes, parce qu'il avait l'air complet.
TypeScript, c'est JavaScript plus une chose : des types, un contrat écrit, vérifié par une machine, avant que le code tourne. Le même bug, en TypeScript, est souligné en rouge dans ton éditeur au moment où tu l'écris.
Définition : TypeScript est un sur-ensemble de JavaScript : tout code JS valide est du TS valide. On y ajoute des annotations de type (total: number), un compilateur les vérifie, puis les efface pour produire du JavaScript normal. Le navigateur, lui, ne voit jamais TypeScript ; il exécute du JS.
La même fonction, mais avec la signature TypeScript function appliquerCoupon(total: number, code: string): number (elle promet de renvoyer un number). À ton avis : que dit le compilateur sur le chemin sans return ? Et à quel moment te le dit-il ?
Voir la réponse
Le compilateur refuse : la fonction promet un number, mais un de ses chemins n'a pas de return (donc renvoie undefined), avec l'erreur « Function lacks ending return statement… ». Et il te le dit avant toute exécution : dans l'éditeur, à la frappe, ou à la compilation. Le bug du « cas sur dix » est mort avant d'exister. Tu vas le voir en vrai dans le labo ci-dessous.
Un type, c'est un contrat vérifié par une machine
En JavaScript, les attentes sont dans ta tête : « cette fonction prend un nombre et renvoie un nombre ». Personne ne vérifie. En TypeScript, tu écris cette attente, et le compilateur la fait respecter, pour toi, pour tes collègues, et pour l'IA qui te génère du code :
function appliquerCoupon(total: number, code: string): number {
// ↑ contrat d'entrée ↑ contrat de sortie
...
}
appliquerCoupon('cent', ''); // ✗ refusé : 'cent' n'est pas un number
appliquerCoupon(100); // ✗ refusé : il manque un argument
Chaque annotation est une promesse, et le compilateur est l'huissier : tout appel, tout chemin de code, toute affectation est vérifiée contre le contrat. Pas par relecture humaine, mais par une machine, à chaque frappe, sans fatigue. Ça doit te rappeler quelque chose : c'est le même rôle que tes tests (cours Tester son code), mais joué encore plus tôt, avant même d'exécuter quoi que ce soit.
L'angle IA, dès maintenant : les types sont un contrat lisible par la machine, donc aussi par l'IA. Quand tes fonctions sont typées, l'assistant génère du code qui respecte le contrat (il le voit dans le contexte), et tout écart est souligné immédiatement par le compilateur au lieu d'exploser en prod. Typer, c'est cadrer l'IA.
À toi : fais taire le compilateur
Voici un vrai compilateur TypeScript, chargé dans ton navigateur. Clique sur Vérifier les types : il va trouver l'erreur, sans exécuter une seule ligne. Lis le message, corrige (il manque un return pour le cas sans promo), et revérifie jusqu'au ✓ 0 erreur. Tu peux aussi cliquer sur Exécuter pour voir ce que le JavaScript aurait fait en silence.
Bloqué sur la correction ? Voir le fix
Ajoute return total; juste avant la fermeture de la fonction (le cas « pas de promo » doit renvoyer le total inchangé). Revérifie : ✓ 0 erreur. Compare avec « Exécuter » avant le fix : le JavaScript affichait tranquillement undefined ; c'est exactement ce silence que TypeScript vient de supprimer.
Le contresens classique : TypeScript ne vérifie rien pendant l'exécution. Les types sont contrôlés à la compilation puis effacés : le navigateur exécute du JavaScript nu. Si une API t'envoie n'importe quoi au runtime, TypeScript ne te protège pas tout seul : on y consacre la leçon 8.
Le compilateur, un filtre avant l'exécution
Garde cette image pour tout le cours : entre ton code et le navigateur, TypeScript installe un filtre. Ce qui passe le filtre devient du JavaScript propre ; ce qui ne le passe pas s'arrête sur ton écran, en rouge, là où c'est le moins cher à corriger :
Et la suite ? Bonne nouvelle : tu n'auras presque jamais à écrire autant d'annotations que tu l'imagines. TypeScript devine la plupart des types tout seul : c'est l'inférence, et c'est la leçon 2.
The bug JavaScript never sees
You know this bug. Everyone knows this bug. A JavaScript function that, one time out of ten, forgets to return something. The code runs, no error, and three functions later a calculation shows NaN or the page crashes on Cannot read properties of undefined — at 2 a.m., on a user's machine, never on yours.
function applyCoupon(total, code) {
if (code === 'PROMO10') {
return total - total * 0.10;
}
// …and if the promo code is empty? The function returns undefined.
}
const toPay = applyCoupon(100, '');
console.log(toPay * 1.2); // NaN — good luck tracking that down
JavaScript will never say anything about this code: it's syntactically perfect. The error will only exist at runtime, on the exact path nobody checked by hand. And if this code was generated by an AI, you may have approved it in three seconds, because it looked complete.
TypeScript is JavaScript plus one thing: types — a written contract, checked by a machine, before the code runs. The same bug, in TypeScript, gets a red underline in your editor the moment you write it.
Definition: TypeScript is a superset of JavaScript: any valid JS is valid TS. You add type annotations (total: number), a compiler checks them, then erases them to produce plain JavaScript. The browser never sees TypeScript — it runs JS.
The same function, but with the TypeScript signature function applyCoupon(total: number, code: string): number (it promises to return a number). Your guess: what does the compiler say about the path with no return? And when does it tell you?
Show the answer
The compiler refuses: the function promises a number, but one of its paths has no return (so returns undefined) — an error like "Function lacks ending return statement…". And it tells you before anything runs: in the editor, as you type, or at compile time. The "one case in ten" bug dies before existing. You'll see it for real in the lab below.
A type is a machine-checked contract
In JavaScript, expectations live in your head: "this function takes a number and returns a number". Nobody checks. In TypeScript, you write that expectation, and the compiler enforces it — for you, for your colleagues, and for the AI generating your code:
function applyCoupon(total: number, code: string): number {
// ↑ input contract ↑ output contract
...
}
applyCoupon('hundred', ''); // ✗ rejected: 'hundred' is not a number
applyCoupon(100); // ✗ rejected: an argument is missing
Every annotation is a promise, and the compiler is the bailiff: every call, every code path, every assignment is checked against the contract. Not by human review — by a machine, on every keystroke, without tiring. That should ring a bell: it's the same role as your tests (the Testing your code course), played even earlier, before anything executes.
The AI angle, right away: types are a contract readable by machines — including the AI. When your functions are typed, the assistant generates code that respects the contract (it sees it in context), and any deviation gets underlined immediately by the compiler instead of blowing up in prod. Typing is how you frame the AI.
Your turn: silence the compiler
Here's a real TypeScript compiler, loaded in your browser. Click Check the types: it will find the error — without executing a single line. Read the message, fix it (a return is missing for the no-promo case), and re-check until ✓ 0 errors. You can also click Run to see what the JavaScript would have done silently.
Stuck on the fix? Show it
Add return total; just before the function's closing brace (the "no promo" case must return the unchanged total). Re-check: ✓ 0 errors. Compare with "Run" before the fix: the JavaScript quietly printed undefined — that's exactly the silence TypeScript just removed.
Beware the classic misconception: TypeScript checks nothing while the code runs. Types are checked at compile time then erased: the browser runs bare JavaScript. If an API sends you garbage at runtime, TypeScript alone won't protect you — lesson 8 is devoted to this.
The compiler, a filter before execution
Keep this image for the whole course: between your code and the browser, TypeScript installs a filter. What passes the filter becomes clean JavaScript; what doesn't stops on your screen, in red, where it's cheapest to fix:
What's next? Good news: you'll almost never write as many annotations as you imagine. TypeScript guesses most types by itself — that's inference, and it's lesson 2.
🎯 Pratique
S'entraîner (clique pour ouvrir) :
💬 Ré-explique sans regarder
Avec tes mots : qu'est-ce que TypeScript ajoute à JavaScript, à quel moment ça agit, et qu'est-ce que le navigateur exécute au final ?
🧠 Rappel libre
Sans remonter : à quel moment TypeScript vérifie-t-il les types, et que reste-t-il des types quand le code s'exécute dans le navigateur ?
⚖️ Juge le code de l'IA
Le compilateur souligne une erreur de type dans le code généré par l'IA. Tu lui demandes de corriger. Elle répond : « Corrigé ! J'ai ajouté as any sur la valeur, l'erreur a disparu. » Tu acceptes, ou tu rejettes ?
as any ne corrige pas l'erreur : il débranche le détecteur de fumée. Le contrat est cassé exactement pareil, mais plus personne ne le surveille : le bug ressortira au runtime, là où c'est le plus cher. L'erreur du compilateur désignait un vrai problème : c'est LUI qu'il faut résoudre (corriger le type, gérer le cas manquant). Le réflexe : quand l'IA « corrige » en faisant taire le compilateur, c'est un faux correctif.Tu as vu le contrat et l'huissier. Mais bonne nouvelle : tu n'auras presque jamais à tout annoter. À la leçon 2, tu découvres l'inférence : TypeScript devine les types tout seul, ainsi que les types de base qui composent tous les autres.
Leçon 2 : Types et inférence →