Leçon 9/10 12 min

Installer TypeScript

npm install, tsconfig et le workflow pro : exécution, vérification des types. De zéro à un projet outillé.

Le moment où le bac à sable ne suffit plus

Jusqu'ici, tout tournait dans le navigateur, dans NOTRE bac à sable. Tu écrivais un bout de code, tu cliquais « Vérifier les types », tu voyais le crayon rouge ou le ✓ vert. Pratique pour apprendre. Mais ton vrai projet, lui, ne vit pas dans une page de cours.

Reprends la saga du cours : le panier, le coupon de réduction qui appliquait -900 € au lieu de -9 €. Ce panier-là, dans la vraie vie, c'est un dossier sur ton disque, avec des dizaines de fichiers, un éditeur ouvert dessus, et une CI qui doit dire « vert » avant que ça parte en prod. Le compilateur ne peut plus être un bouton dans une page : il doit s'installer chez toi, dans ton projet.

Cette leçon, c'est le passage du bac à sable au chantier réel. On va installer TypeScript, générer sa config, et surtout comprendre la question qui sépare les débutants des pros : qui exécute ton code, et qui vérifie tes types ? Ce ne sont pas les mêmes outils. Et savoir ça change tout.

Installer TypeScript et générer sa config

TypeScript s'installe comme une dépendance de développement. C'est cohérent avec la leçon 8 : les types sont effacés à la compilation, le navigateur ne reçoit jamais une ligne de TypeScript. Donc TypeScript n'a aucune raison d'être en production : il sert pendant que tu codes, pas pendant que ton app tourne.

npm install -D typescript

Le -D (raccourci de --save-dev) range TypeScript dans les devDependencies de ton package.json. Maintenant, génère la configuration :

npx tsc --init

Ça crée un tsconfig.json à la racine : le contrat que le compilateur va lire pour savoir comment juger ton code. Avec TypeScript 6.0 (la version stable de 2026), le fichier généré arrive déjà sérieux :

{
  "compilerOptions": {
    "strict": true,
    "module": "nodenext",
    "target": "esnext",
    "types": []
  }
}
  • "strict": true : c'est désormais le défaut. Tous les filets de sécurité sont levés dès le départ (plus de any implicite, plus de null qui passe en douce). C'est exactement le mode de tout ce cours.
  • "module": "nodenext" : la résolution des imports moderne, alignée sur la façon dont Node lit les modules.
  • "target": "esnext" : le JavaScript produit vise la dernière syntaxe ; en pratique, c'est ton bundler ou ton runtime qui adapte ensuite.
  • "types": [] : le piège. Ce tableau vide veut dire « n'inclus aucune définition de type globale automatiquement ». Concrètement, @types/node n'est plus chargé tout seul.

Le "types": [] : sur un projet Node, ce tableau vide te fera planter sur la moindre globale (process, __dirname, Buffer...) avec un message du genre « Cannot find name 'process' ». La cause n'est pas un bug : c'est que @types/node n'est plus inclus automatiquement. Ajoute "types": ["node"] (après avoir installé npm install -D @types/node) et tout rentre dans l'ordre.

La grande idée : séparer qui exécute de qui vérifie

Voici le cœur de la leçon, et le réflexe qui te fera passer pour quelqu'un qui sait. Dans un projet moderne, deux métiers différents regardent ton code TypeScript, et ils ne font pas le même travail.

Qui vérifie tes types

D'abord ton éditeur. Quand tu ouvres VS Code, un serveur TypeScript (le « TS server ») tourne en arrière-plan et souligne tes erreurs en temps réel, à la frappe. C'est le relecteur qui lit par-dessus ton épaule. Mais attention : c'est un confort, pas une garantie. Personne ne te force à regarder les soulignements rouges.

La garantie, c'est la commande canonique :

npx tsc --noEmit

Le --noEmit dit : « vérifie absolument tout, mais ne produis aucun fichier ». C'est le détective qui passe tout le dossier au peigne fin et rend un rapport : 0 erreur, ou rouge. C'est CETTE commande que tu mets dans ta CI et que tu lances avant un commit. Elle ne fabrique rien, elle juge.

Qui exécute ton code

Et là, surprise : ce n'est presque jamais tsc. L'outil qui fait tourner ton code ne perd pas de temps à vérifier les types, il les efface et exécute le JavaScript restant. C'est rapide, et c'est voulu.

  • Côté front : Vite. Il utilise esbuild, qui transpile en retirant les types sans les vérifier. C'est délibéré : Vite optimise la vitesse de rechargement, pas la rigueur. La vérification, c'est le job de l'éditeur et de tsc --noEmit à côté.
  • Côté back : tsx ou Node natif. Tu peux lancer npx tsx script.ts. Et depuis Node 22.18, node script.ts fonctionne directement, sans aucun flag : c'est stable dans Node 24 LTS. Node efface les types et exécute, point.

Pourquoi « exécuter » n'a-t-il jamais besoin de « vérifier » ? Relis la leçon 8 : les types sont effacés. Une fois retirés, il ne reste que du JavaScript, et le JavaScript se contente de tourner. Vérifier les types est une étape séparée, qui se fait à côté, avant ou en parallèle. Exécuter et vérifier sont deux métiers, deux outils, deux moments.

Le piège du « ça marche chez moi » : comme Node et Vite effacent les types sans les vérifier, ils refusent les constructions TypeScript qui ne sont pas du simple effacement : les enum, les namespace qui contiennent du code, et les paramètres de constructeur (constructor(private x: string)). Ces formes généreraient du JavaScript, donc l'effaceur ne sait pas quoi en faire. Le garde-fou : ajoute "erasableSyntaxOnly": true dans ton tsconfig. Le compilateur t'interdira alors d'écrire ces formes, et tu es sûr que ton code tournera partout (Node, Vite, esbuild) sans surprise.

Prédis avant de lire

Tu viens d'initialiser un projet en strict: true. Le dossier contient encore un vieux panier.js non converti. Tu lances npx tsc --noEmit. Que va-t-il trouver dans ce panier.js ?

Voir la réponse

Rien : il ne le regarde même pas. Par défaut, le compilateur ne traite que les fichiers .ts. Ton panier.js est totalement ignoré, donc zéro erreur signalée dessus, mais aussi zéro protection. Pour que tsc le voie, il faut activer "allowJs": true (cohabitation .js/.ts), et pour qu'il le vérifie, ajouter "checkJs": true ou un commentaire // @ts-check en tête du fichier. C'est exactement la porte d'entrée d'une migration progressive.

Deux colonnes, deux métiers

Garde ce schéma en tête à chaque projet : à gauche, ce qui fait tourner ton code (vite, sans vérifier les types) ; à droite, ce qui juge tes types (sans rien exécuter). Les deux travaillent en parallèle.

Deux colonnes côte à côte. À gauche, « Qui exécute » (rapide, sans check) : Vite, tsx, node script.ts, qui mènent par une flèche à « ton code tourne ». À droite, « Qui vérifie » : l'éditeur et tsc --noEmit, qui mènent par une flèche à « 0 erreur, ou rouge ». Les deux colonnes partent du même fichier panier.ts en haut. panier.ts Qui exécute rapide, sans vérifier les types Vite (esbuild) tsx node script.ts ton code tourne Qui vérifie juge les types, sans exécuter éditeur (TS server, temps réel) tsc --noEmit en CI, avant commit 0 erreur, ou rouge
Exécuter et vérifier : deux colonnes, deux outils. tsc --noEmit est le seul qui garantit zéro erreur de type.

Migrer un projet JavaScript déjà existant

Tu n'arrives pas toujours sur un projet neuf. Souvent, il y a déjà des milliers de lignes de .js qui tournent en prod, et personne ne va tout réécrire en un week-end. La méthode officielle du Handbook TypeScript est progressive, fichier par fichier :

  • "allowJs": true : autorise .js et .ts à cohabiter dans le même projet. Rien ne casse, tu peux convertir au rythme que tu veux.
  • "checkJs": true (ou un // @ts-check en tête d'un fichier précis) : demande à TypeScript de vérifier aussi les .js, en déduisant les types depuis le code et les commentaires JSDoc. Le commentaire fichier par fichier te laisse migrer là où tu veux, sans tout activer d'un coup.
  • Renomme .js en .ts au fur et à mesure, en commençant par les modules les plus critiques. Chaque fichier converti gagne la protection complète du compilateur.

Pour un gros legacy : avec TypeScript 6, strict: true est le défaut, et sur un vieux projet ça peut faire pleuvoir des centaines d'erreurs d'un coup, décourageant. Baisse-le temporairement (passe "strict": false, ou désactive juste strictNullChecks), migre tranquillement, puis remonte la rigueur par étapes une fois le gros du chemin fait. Mieux vaut un mur qu'on grimpe par paliers qu'un mur devant lequel on abandonne.

Ce qui arrive : TypeScript 7

À surveiller : Microsoft réécrit le compilateur TypeScript en Go (projet « tsgo », qui deviendra TypeScript 7). L'objectif annoncé est un compilateur environ 10× plus rapide. Une beta publique est disponible depuis avril 2026 via npx @typescript/native-preview, mais ce n'est pas encore stable et ce n'est pas pour la prod. Pour aujourd'hui, ta référence stable reste TypeScript 6.0 et le tsc classique. Garde juste l'info dans un coin : le jour où tsgo sera stable, tes tsc --noEmit deviendront quasi instantanés.

À toi : de zéro à un projet outillé

Un terminal simulé, dans le dossier de ton panier. Tu vas installer TypeScript, générer la config, lancer la vérification, voir une vraie erreur de type rouge liée à la saga du coupon, puis la corriger et obtenir le vert.

🖥️ Terminal simulé · installer et outiller TypeScript
$

When the sandbox is no longer enough

Until now, everything ran in the browser, in OUR sandbox. You wrote a snippet, clicked "Check the types", saw the red pen or the green ✓. Handy for learning. But your real project doesn't live inside a course page.

Pick up the course saga: the cart, the coupon that applied -€900 instead of -€9. That cart, in real life, is a folder on your disk, with dozens of files, an editor open on it, and a CI that has to say "green" before it ships to prod. The compiler can no longer be a button on a page — it has to install itself on your machine, inside your project.

This lesson is the move from the sandbox to the real building site. We'll install TypeScript, generate its config, and above all understand the question that separates beginners from pros: who runs your code, and who checks your types? These are not the same tools. And knowing that changes everything.

Installing TypeScript and generating its config

TypeScript installs as a development dependency. That's consistent with lesson 8: types are erased at compilation, the browser never receives a single line of TypeScript. So TypeScript has no reason to be in production: it serves while you code, not while your app runs.

npm install -D typescript

The -D (short for --save-dev) files TypeScript under your package.json's devDependencies. Now generate the configuration:

npx tsc --init

This creates a tsconfig.json at the root: the contract the compiler reads to know how to judge your code. With TypeScript 6.0 (the 2026 stable release), the generated file arrives already serious:

{
  "compilerOptions": {
    "strict": true,
    "module": "nodenext",
    "target": "esnext",
    "types": []
  }
}
  • "strict": true — this is now the default. Every safety net is up from the start (no implicit any, no null sneaking through). It's exactly the mode used throughout this course.
  • "module": "nodenext" — modern import resolution, aligned with how Node reads modules.
  • "target": "esnext" — the emitted JavaScript targets the latest syntax; in practice your bundler or runtime adapts it afterwards.
  • "types": [] — the trap. This empty array means "don't include any global type definitions automatically". Concretely, @types/node is no longer loaded on its own.

Beware of "types": []: on a Node project, this empty array will make you crash on the slightest global (process, __dirname, Buffer...) with a message like "Cannot find name 'process'". It's not a bug — it's that @types/node is no longer included automatically. Add "types": ["node"] (after running npm install -D @types/node) and everything falls back into place.

The big idea: separate who runs from who checks

Here's the heart of the lesson, and the reflex that makes you look like someone who knows. In a modern project, two different jobs look at your TypeScript code, and they don't do the same work.

Who checks your types

First, your editor. When you open VS Code, a TypeScript server (the "TS server") runs in the background and underlines your errors in real time, as you type. It's the proofreader reading over your shoulder. But beware: that's a comfort, not a guarantee. Nobody forces you to look at the red squiggles.

The guarantee is the canonical command:

npx tsc --noEmit

The --noEmit says: "check absolutely everything, but produce no file". It's the detective who combs the whole folder and hands back a verdict: 0 errors, or red. This is THE command you put in your CI and run before a commit. It builds nothing — it judges.

Who runs your code

And here's the surprise: it's almost never tsc. The tool that actually runs your code doesn't waste time checking types — it strips them and executes the remaining JavaScript. It's fast, and that's by design.

  • Front side: Vite. It uses esbuild, which transpiles by removing the types without checking them. That's deliberate: Vite optimises reload speed, not strictness. Checking is the job of the editor and tsc --noEmit alongside.
  • Back side: tsx or native Node. You can run npx tsx script.ts. And since Node 22.18, node script.ts works directly, with no flag at all — it's stable in Node 24 LTS. Node erases the types and runs, full stop.

Why does "running" never need "checking"? Re-read lesson 8: types are erased. Once removed, only JavaScript remains, and JavaScript just runs. Checking types is a separate step, done on the side, before or in parallel. Running and checking are two jobs, two tools, two moments.

Beware — the "works on my machine" trap: because Node and Vite erase types without checking them, they reject TypeScript constructs that aren't pure erasure: enums, namespaces that contain code, and constructor parameters (constructor(private x: string)). These forms would emit JavaScript, so the eraser doesn't know what to do with them. The safeguard: add "erasableSyntaxOnly": true to your tsconfig. The compiler will then forbid those forms, and you're sure your code runs everywhere (Node, Vite, esbuild) with no surprises.

Predict before reading on

You just initialised a project in strict: true. The folder still has an old, unconverted cart.js. You run npx tsc --noEmit. What will it find in that cart.js?

Show the answer

Nothing — it doesn't even look at it. By default, the compiler only processes .ts files. Your cart.js is completely ignored, so zero errors reported on it, but also zero protection. For tsc to see it, you enable "allowJs": true (.js/.ts living together), and for it to check it, add "checkJs": true or a // @ts-check comment at the top of the file. That's exactly the entry point for a gradual migration.

Two columns, two jobs

Keep this diagram in mind on every project: on the left, what runs your code (fast, without checking types); on the right, what judges your types (without running anything). The two work in parallel.

Two side-by-side columns. On the left, "Who runs" (fast, no check): Vite, tsx, node script.ts, leading by an arrow to "your code runs". On the right, "Who checks": the editor and tsc --noEmit, leading by an arrow to "0 errors, or red". Both columns start from the same cart.ts file at the top. cart.ts Who runs fast, without checking types Vite (esbuild) tsx node script.ts your code runs Who checks judges types, without running editor (TS server, real time) tsc --noEmit in CI, before commit 0 errors, or red
Running and checking: two columns, two tools. tsc --noEmit is the only one that guarantees zero type errors.

Migrating an existing JavaScript project

You don't always land on a fresh project. Often there are already thousands of lines of .js running in prod, and nobody is going to rewrite it all in a weekend. The official TypeScript Handbook method is gradual, file by file:

  • "allowJs": true — lets .js and .ts live together in the same project. Nothing breaks; you convert at your own pace.
  • "checkJs": true (or a // @ts-check at the top of a specific file) — asks TypeScript to also check the .js files, inferring types from the code and JSDoc comments. The per-file comment lets you migrate where you want, without flipping everything at once.
  • Rename .js to .ts as you go, starting with the most critical modules. Each converted file earns the compiler's full protection.

For a big legacy codebase: with TypeScript 6, strict: true is the default, and on an old project that can rain down hundreds of errors at once — discouraging. Lower it temporarily (set "strict": false, or just disable strictNullChecks), migrate calmly, then raise the strictness back up in stages once the bulk is done. Better a wall you climb in steps than a wall you give up in front of.

What's coming: TypeScript 7

One to watch: Microsoft is rewriting the TypeScript compiler in Go (the "tsgo" project, which will become TypeScript 7). The stated goal is a compiler around 10x faster. A public beta has been available since April 2026 via npx @typescript/native-preview, but it's not stable yet and not for production. For today, your stable reference stays TypeScript 6.0 and the classic tsc. Just keep the info in a corner: the day tsgo is stable, your tsc --noEmit runs become near-instant.

Your turn: from zero to a tooled project

A simulated terminal, in your cart folder. You'll install TypeScript, generate the config, run the check, see a real red type error tied to the coupon saga, then fix it and get the green.

🖥️ Simulated terminal · install and tool up TypeScript
$

🎯 Pratique

S'entraîner (clique pour ouvrir) :

💬 Ré-explique sans regarder
Ré-explique sans regarder

Explique à un collègue pourquoi « exécuter ton code » et « vérifier tes types » sont deux outils différents, avec un exemple de chaque côté.

Une bonne explication dit : les types sont effacés, donc exécuter n'a jamais besoin de les vérifier. Qui exécute (Vite, tsx, node script.ts) retire les types sans les contrôler, pour la vitesse. Qui vérifie (l'éditeur en temps réel, et surtout tsc --noEmit en CI) juge tout sans rien produire. La garantie « 0 erreur » vient de tsc --noEmit, pas de Vite.
🧠 Rappel libre
Rappel libre

Sans remonter : que fait précisément npx tsc --noEmit, et pourquoi est-ce LA commande de la CI ?

tsc --noEmit vérifie tous tes fichiers TypeScript et ne produit aucun fichier : il juge, il ne fabrique pas. Verdict binaire : 0 erreur, ou rouge. C'est LA commande de la CI parce que les outils qui exécutent (Vite, Node) effacent les types sans les vérifier : sans tsc --noEmit, personne ne garantit qu'il n'y a aucune erreur de type avant la prod.
⚖️ Juge le code de l'IA
Accepter ou rejeter le code de l'IA

Ta CI ne bloque pas les erreurs de type d'un projet Vite. Tu demandes à l'IA de régler ça. Elle répond : « Réglé ! J'ai ajouté vite build dans la CI, ça compile le projet et ça plantera si un type est faux. » Tu acceptes, ou tu rejettes ?

À rejeter : vite build utilise esbuild, qui efface les types sans les vérifier. Une erreur de type ne fera donc PAS échouer le build : la CI resterait verte sur du code faux. Le bon fix : ajouter npx tsc --noEmit comme step dédié de la CI. C'est le seul outil qui vérifie réellement les types et rend un verdict binaire. Règle d'or : ce qui exécute n'est pas ce qui vérifie.
Pourquoi installe-t-on TypeScript avec npm install -D et pas en dépendance normale ?
Ton tsconfig fraîchement généré contient "types": [] et ton projet Node plante sur « Cannot find name 'process' ». Que fais-tu ?
node script.ts refuse de tourner à cause d'un enum dans ton code. Pourquoi, et quel garde-fou évite ce piège ?
Ta CI doit attraper les erreurs de type d'un projet Vite. Quelle commande ajoutes-tu, et pourquoi pas simplement vite build ?
Prochaine étape

Ton projet est outillé : compilateur installé, tsconfig en place, qui exécute et qui vérifie bien séparés. Leçon 10, la dernière : TS dans la vraie vie. any contre unknown, typer le DOM et les réponses d'API sans se faire avoir, et le workflow TS quand tu codes avec l'IA.

Leçon 10 : TS dans la vraie vie →
Besoin d'un développeur pour votre projet ?

Réponse sous 24h · Sans engagement