L'essentiel en une minute
Apprendre TypeScript prend peu de temps quand on connaît déjà JavaScript : c'est le même langage, avec des types vérifiés avant l'exécution. Ce guide part de là. Si les variables, les fonctions, map ou async/await ne vous sont pas encore familiers, commencez par notre guide pour apprendre JavaScript : nous ne reprenons pas ces bases ici.
Chaque exemple a été vérifié avec le compilateur TypeScript 7.0.2 et exécuté avec Node.js 22.15.0 et l'option --experimental-strip-types ; les erreurs affichées sont celles que le compilateur a produites. Versions et chiffres viennent de sources officielles lues le 31 octobre 2026.
Points clés
- TypeScript vérifie les types avant l'exécution, puis les efface : il ne valide pas les données reçues.
- La version courante est TypeScript 7.0.2, un compilateur natif que Microsoft annonce de 8 à 12 fois plus rapide sur une compilation complète.
- Node.js exécute un fichier
.tssans option depuis la version 22.18.0, si le code n'utilise que de la syntaxe effaçable, et sans vérifier les types.- À apprendre en premier : inférence, interfaces, unions, rétrécissement, génériques, et
unknownplutôt queany.- Un projet JavaScript se migre fichier par fichier, avec
checkJset JSDoc d'abord.
Ce que TypeScript ajoute à JavaScript, et ce qu'il ne fait pas
TypeScript est une surcouche de JavaScript : il ajoute une syntaxe de types, un vérificateur qui la contrôle avant l'exécution, et un outillage d'éditeur qui s'en sert. Le reste est du JavaScript.
Ce qu'il apporte, concrètement :
- Des types statiques. Un appel avec une chaîne là où un
numberest attendu est signalé avant l'exécution. - Des erreurs à la compilation. Propriété mal orthographiée, valeur peut-être
undefined, argument oublié :tscles trouve sans exécuter le code. - Un éditeur plus utile. Autocomplétion, renommage sûr et navigation s'appuient sur les types, dans VS Code ou un autre IDE.
Ses limites sont aussi importantes à comprendre pour apprendre TypeScript sans malentendu :
- Les types sont effacés à l'exécution. Le code n'est pas plus rapide, et rien n'est vérifié pendant qu'il tourne.
- Aucune validation des données externes. Une requête HTTP ou un fichier JSON arrivent sans garantie ; écrire
as Utilisateurne vérifie rien. -
anydésactive tout. Une valeuranyn'est plus contrôlée, et l'erreur ressort à l'exécution.
Pour les données externes, il faut une validation à l'exécution. Notre tutoriel pour créer une API REST avec Node.js et Express utilise Zod, une bibliothèque qui valide les données et dont on peut dériver les types TypeScript.
Qui utilise TypeScript ?
TypeScript est sixième de l'enquête Stack Overflow 2026, utilisé par 43,8 % des 14 099 répondants à la question sur les langages (Stack Overflow Developer Survey 2026, consulté le 31 octobre 2026). C'est un usage déclaré, pas une mesure du marché.
Selon le rapport Octoverse 2026 de GitHub, TypeScript reste le premier langage par nombre de contributeurs. De septembre 2025 à septembre 2026, il a gagné 3,62 millions de contributeurs mensuels, contre 3,23 millions pour Python et 1,82 million pour JavaScript (GitHub Octoverse 2026, 28 octobre 2026).
Le rapport compte les comptes actifs chaque mois, dépôts privés inclus, et un même compte peut compter pour plusieurs langages.
TypeScript vs JavaScript : le tableau des différences
La différence entre TypeScript et JavaScript tient au moment où les erreurs de type sont détectées : avant l'exécution pour TypeScript, pendant pour JavaScript.
| Critère | JavaScript | TypeScript |
|---|---|---|
| Typage | Dynamique, vérifié à l'exécution | Statique, vérifié avant l'exécution, puis effacé |
| Exécution | Directe dans le navigateur et Node.js | Compilé en JavaScript, ou types retirés par Node.js |
Erreur "5" + 3 | Silencieuse, donne "53" | Signalée si un number est attendu |
| Validation des données externes | À écrire soi-même | À écrire soi-même aussi (Zod, Valibot, contrôles manuels) |
| Éditeur | Autocomplétion approximative | Autocomplétion, renommage et navigation fondés sur les types |
| Performances à l'exécution | Référence | Identiques : c'est le même JavaScript qui tourne |
| Projets adaptés | Scripts, prototypes, petites pages | Code partagé en équipe, bibliothèques, applications qui durent |
TypeScript n'accélère donc pas l'exécution : il réduit les erreurs qui l'atteignent. Le chiffre de 15 % de bugs évités, souvent cité, vient d'une étude de Zheng Gao, Christian Bird et Earl T. Barr présentée à la conférence ICSE 2017. Après avoir annoté à la main le code de 400 bugs publics de projets JavaScript sur GitHub, ils estiment que TypeScript 2.0 et Flow 0.30 en détectaient chacun 60, soit 15 % (intervalle de confiance à 95 % : 11,5 % à 18,5 %) (« To Type or Not to Type », ICSE 2017, DOI 10.1109/ICSE.2017.75).
Réserves : l'étude porte sur TypeScript 2.0, ne compte que des bugs déjà publiés (ce qui, selon les auteurs, sous-estime l'effet) et mesure des bugs détectables, pas évités.
Installer TypeScript 7 et configurer tsconfig
TypeScript s'installe dans chaque projet, comme dépendance de développement. Le registre npm sert la version 7.0.2 sous l'étiquette latest (consulté le 31 octobre 2026), et le site officiel indique « currently 7.0 ».
npm install --save-dev typescript npx tsc --version # -> Version 7.0.2 npm pkg set type=module La dernière commande ajoute "type": "module" au package.json. Sans elle, avec la configuration ci-dessous, tsc traite vos fichiers comme du CommonJS et refuse import et export (erreurs TS1295 et TS1287 dans notre essai).
Ce qui change avec TypeScript 7
TypeScript 7 est une réécriture du compilateur en code natif. Selon son annonce, il donne « typiquement des accélérations entre 8x et 12x sur les compilations complètes » (blog de TypeScript, 8 juillet 2026, notre traduction). Ce sont des mesures de Microsoft (équipe TypeScript) ; le graphique reprend les cinq projets publiés, de 7,7x à 11,9x.
Trois conséquences pour qui débute en 2026 :
-
strictest activé par défaut depuis TypeScript 6.0, etmodulevautesnext. Les options dépréciées en 6.0, commetarget: es5oubaseUrl, sont devenues des erreurs. - Le compilateur n'expose pas encore d'API programmable. Le contrôle des gabarits Vue, Svelte, Angular, Astro ou MDX n'est donc pas encore pris en charge et ces outils restent sur TypeScript 6.0. TypeScript 7.1, en bêta depuis le 20 octobre 2026, doit apporter une nouvelle API (annonce de TypeScript 7.1 Beta).
- L'éditeur. L'annonce indique que VS Code dispose d'une extension dédiée à TypeScript 7. Pour bien équiper l'éditeur par ailleurs, voyez notre sélection d'extensions VS Code.
Le tsconfig.json essentiel
npx tsc --init génère un fichier commenté qui active notamment strict et noUncheckedIndexedAccess, et fixe "types": [] : pour Node.js, ajoutez "types": ["node"] et installez @types/node.
Voici la configuration utilisée pour nos exemples, celle que recommande la documentation de Node.js, plus strict et skipLibCheck :
{ "compilerOptions": { "target": "esnext", "module": "nodenext", "strict": true, "noEmit": true, "erasableSyntaxOnly": true, "verbatimModuleSyntax": true, "rewriteRelativeImportExtensions": true, "skipLibCheck": true } } | Option | Rôle |
|---|---|
strict | Toutes les vérifications strictes, dont noImplicitAny |
noEmit | Vérifie sans produire de fichiers .js |
erasableSyntaxOnly | Refuse la syntaxe que Node.js ne sait pas effacer, comme enum |
verbatimModuleSyntax | Impose import type pour les imports de types |
rewriteRelativeImportExtensions | Autorise les imports en .ts et les réécrit en .js lors d'une compilation |
Exécuter un fichier .ts directement avec Node.js
Node.js sait retirer les annotations d'un fichier .ts et exécuter le JavaScript restant. Selon sa documentation, cette suppression des types est activée par défaut depuis les versions 23.6.0 et 22.18.0, et elle est déclarée stable depuis les versions 25.2.0 et 24.12.0 (TypeScript dans Node.js, consulté le 31 octobre 2026).
node bases.ts # Node.js 22.18.0 ou plus récent npx tsc --noEmit # la vérification des types, à lancer à part Quatre règles évitent les surprises :
- Node.js ne vérifie pas les types. Sa page d'apprentissage recommande
npx tsc --noEmità côté. - Seule la syntaxe effaçable passe.
enum, les propriétés de paramètres, lesnamespacequi contiennent du code et les aliasimport x = require(...)demandent une transformation. L'option--experimental-transform-types, qui contournait cette limite, a été retirée dans Node.js 26.0.0. - L'extension est obligatoire dans les imports :
import "./fichier.ts", pasimport "./fichier". - Les imports de types portent le mot-clé
type, sinon le programme échoue.
Les fichiers .tsx et les paths du tsconfig ne sont pas pris en charge non plus : dans ce cas, compilez avec tsc ou un outil de build.
Apprendre TypeScript par les notions clés
Ces exemples passent tous tsc avec la configuration ci-dessus ; // -> indique la sortie obtenue. C'est l'ordre que nous conseillons pour apprendre TypeScript.
Annotations et inférence
const prenom: string = "Inès"; let score = 10; // type inféré : number const langage = "TypeScript"; // type inféré : "TypeScript" function prixTTC(prixHT: number, taux: number = 0.2): number { return prixHT * (1 + taux); } score = score + 5; console.log(`${prenom} a ${score} points`); // -> Inès a 15 points console.log(prixTTC(100), langage); // -> 120 TypeScript N'annotez pas tout. TypeScript déduit le type de score de sa valeur initiale. Annotez surtout les paramètres de fonctions et les valeurs de retour publiques : c'est là que les types documentent votre code.
Interfaces et alias de type
interface Utilisateur { id: number; nom: string; email?: string; // propriété facultative } interface Admin extends Utilisateur { droits: string[]; } type Point = { x: number; y: number }; const ada: Admin = { id: 1, nom: "Ada", droits: ["publier"] }; console.log(ada.nom, ada.email ?? "pas d'e-mail"); // -> Ada pas d'e-mail Le manuel officiel note qu'une interface peut être rouverte pour recevoir de nouvelles propriétés, pas un alias type, et propose une règle : utiliser interface jusqu'à avoir besoin d'une fonction propre à type (par exemple une union) (Everyday Types, notre traduction).
Unions, types littéraux et rétrécissement
type Role = "admin" | "editeur" | "lecteur"; // union de types littéraux function formater(valeur: string | number): string { if (typeof valeur === "number") { return valeur.toFixed(2); // ici, valeur est un number } return valeur.toUpperCase(); // ici, valeur est une string } type Resultat = | { ok: true; valeur: number } | { ok: false; erreur: string }; function afficher(r: Resultat): string { return r.ok ? `Valeur : ${r.valeur}` : `Erreur : ${r.erreur}`; } console.log(formater(3.14159), formater("ts")); // -> 3.14 TS console.log(afficher({ ok: false, erreur: "fichier introuvable" })); // -> Erreur : fichier introuvable Le rétrécissement (narrowing) est le cœur de TypeScript au quotidien : après un test typeof, in ou sur une propriété commune comme ok, le compilateur sait quel membre de l'union vous manipulez.
Pour qu'un switch traite tous les cas d'une union, ajoutez une vérification d'exhaustivité avec le type never :
type Forme = | { type: "cercle"; rayon: number } | { type: "carre"; cote: number }; function aire(f: Forme): number { switch (f.type) { case "cercle": return Math.PI * f.rayon ** 2; case "carre": return f.cote ** 2; default: { const jamais: never = f; // erreur si un cas est oublié return jamais; } } } console.log(aire({ type: "carre", cote: 3 }).toFixed(2)); // -> 9.00 Si l'on ajoute { type: "triangle"; base: number; hauteur: number } à l'union sans nouveau case, tsc répond : « Impossible d'assigner le type '{ type: "triangle"; base: number; hauteur: number; }' au type 'never' » (TS2322).
Les génériques
function premier<T>(liste: T[]): T | undefined { return liste[0]; } interface Reponse<T> { statut: number; donnees: T; } const n = premier([10, 20, 30]); // number | undefined const r: Reponse<string[]> = { statut: 200, donnees: ["ok"] }; console.log(n, r.donnees.length); // -> 10 1 Un générique est un type en paramètre. premier fonctionne pour toute liste et conserve le type de ses éléments, là où any le perdrait.
Les types utilitaires
interface Article { id: number; titre: string; contenu: string; publie: boolean } type MiseAJour = Partial<Article>; // tout devient facultatif type Apercu = Pick<Article, "id" | "titre">; // garde deux propriétés type NouvelArticle = Omit<Article, "id">; // retire id type Compteurs = Record<"vues" | "partages", number>; const apercu: Readonly<Apercu> = { id: 7, titre: "Apprendre TypeScript" }; Ils évitent de recopier une interface pour chaque variante. Partial sert aux mises à jour partielles d'une API, Omit aux données de création sans identifiant.
L'opérateur satisfies vérifie qu'une valeur respecte un type sans perdre le type précis de chaque propriété :
type Couleur = "rouge" | "vert" | "bleu"; const palette = { rouge: "#e11d48", vert: [34, 197, 94], } satisfies Partial<Record<Couleur, string | number[]>>; console.log(palette.rouge.toUpperCase()); // -> #E11D48 console.log(palette.vert.join(", ")); // -> 34, 197, 94 Une clé jaune serait refusée (TS2353). Avec une simple annotation de type, palette.rouge.toUpperCase() échouerait (TS18048 et TS2339).
enum ou union de littéraux ?
Préférez une union de littéraux, ou un objet as const, à enum. Avec erasableSyntaxOnly, tsc refuse enum (erreur TS1294), et Node.js 22.15.0 échoue avec ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX : « TypeScript enum is not supported in strip-only mode ». L'alternative fonctionne partout :
const Statut = { Brouillon: "brouillon", Publie: "publie" } as const; type Statut = (typeof Statut)[keyof typeof Statut]; // "brouillon" | "publie" const s: Statut = Statut.Publie; console.log(s); // -> publie any ou unknown ?
any accepte tout et ne vérifie plus rien. Le code suivant passe tsc en mode strict sans la moindre erreur, puis plante :
let donnee: any = "texte"; donnee.toFixed(2); // -> TypeError: donnee.toFixed is not a function unknown accepte tout aussi, mais interdit de s'en servir avant de l'avoir vérifié. Appeler .toUpperCase() sur une valeur unknown produit l'erreur TS18046. Voici la bonne façon d'en sortir, avec une fonction de garde :
const brut: unknown = JSON.parse('{"nom": "Ada", "age": 36}'); function estPersonne(x: unknown): x is { nom: string; age: number } { return typeof x === "object" && x !== null && "nom" in x && typeof x.nom === "string" && "age" in x && typeof x.age === "number"; } if (estPersonne(brut)) { console.log(`${brut.nom}, ${brut.age} ans`); // -> Ada, 36 ans } Valider à l'exécution avec Zod
Écrire ces gardes à la main devient vite pénible. Zod décrit le schéma une fois, valide à l'exécution et fournit le type :
import * as z from "zod"; const Inscription = z.object({ email: z.email(), age: z.number().int().min(16), }); type Inscription = z.infer<typeof Inscription>; // { email: string; age: number } const recu: unknown = JSON.parse('{"email": "ada@example.com", "age": "36"}'); const resultat = Inscription.safeParse(recu); if (!resultat.success) { console.log(z.flattenError(resultat.error).fieldErrors); // -> { age: [ 'Invalid input: expected number, received string' ] } } Le compilateur ne pouvait pas voir que age arrivait sous forme de chaîne : seule la validation à l'exécution l'a détecté. Exemple exécuté avec Zod 4.6.7, la version servie par le registre npm le 31 octobre 2026.
Migrer un petit projet JavaScript en 4 étapes
Nous avons déroulé une migration sur un projet de deux fichiers qui calcule un panier. Le bug est classique : des frais de port lus dans un formulaire arrivent sous forme de chaîne. Fichier src/panier.js :
export function total(articles, fraisPort) { const sousTotal = articles.reduce((somme, a) => somme + a.prix * a.quantite, 0); return sousTotal + fraisPort; } Fichier src/main.js :
import { total } from "./panier.js"; const panier = [{ nom: "Clavier", prix: 49.9, quantite: 1 }]; const fraisSaisis = "4.90"; // valeur lue dans un champ de formulaire console.log(total(panier, fraisSaisis)); // -> 49.94.90 Étape 1 : installer TypeScript et vérifier le JavaScript tel quel. Le package.json contient déjà "type": "module". Un tsconfig.json avec "allowJs": true, "checkJs": true, "noEmit": true et "strict": false fait analyser les fichiers .js sans les modifier. Sur ce projet, npx tsc ne signale rien : sans annotations, le compilateur ne sait pas ce que fraisPort doit contenir.
Étape 2 : ajouter des types en JSDoc. Les commentaires JSDoc donnent des types sans changer d'extension :
/** * @typedef {{ nom: string, prix: number, quantite: number }} Article * @param {Article[]} articles * @param {number} fraisPort * @returns {number} *...


