À propos de ce cours
Cette leçon présente les langages transpilés en JavaScript. Elle définit la transpilation et la distingue de la compilation, retrace l’histoire de ces langages et les classe en quatre familles. Elle montre ensuite CoffeeScript et Babel, puis surtout TypeScript : installation, compilation avec tsc, lecture des erreurs, effacement des types, exécution avec Node.js, choix de la version de JavaScript produite, outils qui traduisent sans vérifier, fichier tsconfig.json, projet pour le navigateur et source maps. Sept activités corrigées et testées terminent la leçon.
-
Objectifs
- Expliquer ce qu'est la transpilation et la différence avec la compilation classique
- Citer les grandes familles de langages transpilés en JavaScript (TypeScript, CoffeeScript, Dart, Elm…) et leur histoire
- Installer TypeScript, compiler un fichier
.tset lire les messages d'erreur detsc - Comprendre que les types disparaissent à l'exécution et ce que cela implique
- Distinguer les outils qui vérifient (tsc) de ceux qui traduisent seulement (esbuild, Babel, Node.js)
- Configurer un projet avec
tsconfig.jsonet utiliser une page web qui charge le JavaScript produit
-
Présentation
- Dans la leçon précédente, vous avez vu que JavaScript évolue au fil des versions d'ECMAScript (ES5, ES6 et suivantes). Mais le navigateur, lui, n'exécute qu'un seul langage de programmation: JavaScript (plus le WebAssembly, un format binaire).
- Pourtant, beaucoup de développeurs n'écrivent pas directement leur code en JavaScript : ils écrivent en TypeScript, en Dart, en Elm… puis un outil traduit ce code en JavaScript. On parle de langages transpilés en JavaScript.
- Pourquoi ce détour ? Pour détecter les erreurs avant l'exécution, pour bénéficier d'une syntaxe plus agréable, ou pour utiliser le JavaScript le plus récent tout en restant compatible avec d'anciens navigateurs.
- Tous les exemples de cette leçon ont été exécutés avec TypeScript 7.0.2, Node.js 22.23, Babel 8.1, CoffeeScript 2.7.1 et esbuild 0.28. Les sorties de terminal reproduites sont les sorties réelles. Les fichiers sont fournis dans l'archive de la leçon (dossier
exemples/).

-
Qu'est-ce que la transpilation ?
- Compiler, au sens classique, c'est traduire un programme écrit dans un langage de haut niveau (C, Rust, Go) en code machine, que le processeur exécute directement. Le résultat n'est plus lisible par un humain.
- Transpiler (contraction de translate et compile), c'est traduire un langage de haut niveau en un autre langage de haut niveau. Le résultat reste du code source, lisible : ici, du JavaScript.
- On parle aussi de transpilation quand on traduit JavaScript vers JavaScript: du JavaScript récent (ES2022) vers une version plus ancienne (ES5) comprise par de vieux navigateurs.

- La frontière n'est pas stricte : la documentation de TypeScript parle de compilateur (
tscsignifie TypeScript Compiler). Les deux mots sont acceptés ; « transpiler » précise simplement que la cible est un langage de haut niveau. - Une transpilation se fait une seule fois, sur la machine du développeur ; le navigateur de l'utilisateur ne reçoit que le résultat en JavaScript.
-
Une brève histoire des langages transpilés
- À la fin des années 2000, JavaScript est en retard : pas de classes, pas de modules, une syntaxe jugée lourde. ES5 (2009) ne règle pas tout, et ES6 n'arrivera qu'en 2015. Des développeurs créent alors des langages qui produisent du JavaScript:
- CoffeeScript (2009) propose une syntaxe courte, sans accolades ni points-virgules ;
- Dart (Google, 2011) et ClojureScript (2011) apportent des langages complets ;
- TypeScript (Microsoft, 2012) ajoute des types à JavaScript ; Elm (2012) mise sur la programmation fonctionnelle ;
- 6to5 (2014), renommé Babel en 2015, permet d'écrire le JavaScript de demain dès aujourd'hui.
- À la fin des années 2000, JavaScript est en retard : pas de classes, pas de modules, une syntaxe jugée lourde. ES5 (2009) ne règle pas tout, et ES6 n'arrivera qu'en 2015. Des développeurs créent alors des langages qui produisent du JavaScript:

- Plusieurs idées de CoffeeScript (fonctions fléchées, classes, gabarits de chaîne) sont entrées dans JavaScript avec ES2015 : les langages transpilés servent aussi de laboratoire au langage officiel.
- Depuis 2025, Node.js sait exécuter directement des fichiers
.ts; en 2026, TypeScript 7 a remplacé son compilateur écrit en JavaScript par une version écrite en Go, environ dix fois plus rapide.
-
Quatre familles de langages transpilés
- On peut ranger les langages transpilés en JavaScript en quatre familles, selon ce qu'ils apportent :


- Aujourd'hui, TypeScript domine très largement: Angular est écrit en TypeScript, et React, Vue, Svelte ou Node.js le prennent en charge directement. C'est sur lui que porte la suite de la leçon.
-
Exemple 1 : CoffeeScript, une autre syntaxe
- CoffeeScript remplace les accolades par l'indentation (comme Python) et supprime les points-virgules. Voici un petit programme qui calcule une moyenne et filtre les notes :
# notes.coffee : CoffeeScript, un langage transpilé en JavaScript (2009)
notes = [12, 15, 9, 17]
moyenne = (liste) ->
total = 0
total += n for n in liste
total / liste.length
admis = (n for n in notes when n >= 10)
console.log "Moyenne : #{moyenne(notes)}"
console.log "Notes ≥ 10 : #{admis.join(', ')}"
- On le compile avec
npx coffee -c -b notes.coffee: l'outil produitnotes.js, du JavaScript ordinaire, que l'on exécute avec Node.js ou dans une page web.

- La ligne
admis = (n for n in notes when n >= 10)devient une fonction de neuf lignes : un transpileur peut produire beaucoup de code à partir d'une écriture très courte.
-
TypeScript : JavaScript avec des types
- TypeScript est un sur-ensemble de JavaScript : tout code JavaScript valide est aussi du TypeScript valide. On y ajoute des annotations de type (
: string,: number) et des interfaces qui décrivent la forme des objets. - Pour l'installer dans un projet (Node.js doit être installé) :
- TypeScript est un sur-ensemble de JavaScript : tout code JavaScript valide est aussi du TypeScript valide. On y ajoute des annotations de type (
npm init -y
npm install -D typescript
npx tsc -v
- Voici un premier fichier,
bonjour.ts:
// bonjour.ts : un premier fichier TypeScript
interface Eleve {
nom: string;
note: number;
}
function mention(eleve: Eleve): string {
if (eleve.note >= 16) return "Très bien";
if (eleve.note >= 12) return "Bien";
return eleve.note >= 10 ? "Passable" : "Insuffisant";
}
const amel: Eleve = { nom: "Amel", note: 15 };
console.log(`${amel.nom} : ${amel.note}/20 (${mention(amel)})`);

npx tsc bonjour.tsn'affiche rien quand tout va bien : il crée simplementbonjour.js, à côté du fichier source.
-
Les types disparaissent à l'exécution
- Ouvrons le fichier
bonjour.jsproduit par tsc : l'interface et toutes les annotations de type ont disparu. Il ne reste que du JavaScript.
- Ouvrons le fichier

- C'est le principe de l'effacement des types (type erasure) : les types servent pendant le développement, pour vérifier le code ; ils n'existent plus quand le programme s'exécute.
- Conséquence importante : TypeScript ne peut pas vérifier les données qui arrivent pendant l'exécution (saisie de l'utilisateur, fichier JSON, réponse d'un serveur). Pour elles, il faut écrire des vérifications en JavaScript (voir l'activité 6).
-
Détecter les erreurs avant l'exécution
- Le grand intérêt de TypeScript : il trouve des erreurs avant que le programme ne tourne. Le fichier suivant contient cinq erreurs courantes :
// erreurs.ts : TypeScript signale les erreurs AVANT l'exécution
interface Eleve {
nom: string;
note: number;
}
const karim: Eleve = { nom: "Karim", note: "14" }; // 1. une chaîne au lieu d'un nombre
function moyenne(notes: number[]): number {
return notes.reduce((s, n) => s + n, 0) / notes.length;
}
moyenne([12, 15, "18"]); // 2. un élément du mauvais type
console.log(karim.prenom); // 3. une propriété qui n'existe pas
function doubler(x) { // 4. un paramètre sans type
return x * 2;
}
const trouve = [karim].find((e) => e.nom === "Sana");
console.log(trouve.note); // 5. peut-être undefined

| Code | Message (traduit) | Erreur |
|---|---|---|
| TS2322 | Le type 'string' n'est pas affectable au type 'number' | 1 et 2 : une chaîne "14" là où un nombre est attendu |
| TS2339 | La propriété 'prenom' n'existe pas sur le type 'Eleve' | 3 : faute de nom de propriété |
| TS7006 | Le paramètre 'x' a implicitement le type 'any' | 4 : en mode strict, chaque paramètre doit avoir un type |
| TS18048 | 'trouve' est peut-être 'undefined' | 5 : find() peut ne rien trouver |
- Chaque message indique le fichier, la ligne et la colonne (
erreurs.ts:7:38), puis souligne l'endroit exact. - Attention : par défaut, tsc produit quand même le fichier JavaScript, malgré les erreurs. Pour l'en empêcher, on ajoute l'option
--noEmitOnError:

- Et si l'on exécute ce JavaScript produit malgré tout ? L'erreur n°5, annoncée par tsc, se produit réellement :
TypeError: Cannot read properties of undefined. TypeScript l'avait prédite avant l'exécution.
-
Exécuter du TypeScript avec Node.js
- Depuis la version 22.18 (2025), Node.js peut exécuter directement un fichier
.ts:node bonjour.ts. Il retire les types (type stripping) puis exécute le JavaScript restant. - Mais Node.js ne vérifie pas les types. Sur
erreurs.ts, il démarre sans rien dire… et le programme plante à la ligne 21 :
- Depuis la version 22.18 (2025), Node.js peut exécuter directement un fichier

- Node.js sait seulement effacer des types. Une construction TypeScript qui doit être traduite en code, comme un
enum, est refusée :
enum Couleur { Rouge, Vert }
console.log(Couleur.Vert);

- Pour un script rapide,
node fichier.tsest pratique ; pour vérifier son code, il faut toujours passer partsc.
-
Choisir la version de JavaScript produite
- L'option
--targetde tsc indique quelle version d'ECMAScript produire. Avec une cible récente, le code est presque recopié ; avec une cible ancienne, les syntaxes trop récentes sont réécrites.
- L'option
// moderne.ts : des syntaxes récentes de JavaScript, écrites en TypeScript
class Compteur {
#valeur = 0; // champ privé (ES2022)
static creer(depart?: number): Compteur {
const c = new Compteur();
c.#valeur = depart ?? 0; // ?? : opérateur de coalescence (ES2020)
return c;
}
incrementer(pas = 1): number {
return (this.#valeur += pas);
}
}
const config: { pas?: number } = {};
const c = Compteur.creer(10);
console.log(c.incrementer(config.pas ?? 5)); // 15
console.log(config?.pas?.toFixed(2)); // undefined : chaînage optionnel (ES2020)

- La sortie
es2015passe de 17 à 34 lignes : le champ privé#valeurest simulé par unWeakMap, l'opérateur??devient une double comparaison ànulletundefined. - Depuis TypeScript 7, la cible la plus ancienne est ES2015; ES5 n'est plus proposée :

-
Babel : du JavaScript récent pour d'anciens navigateurs
- Babel est un transpileur de JavaScript vers JavaScript. On lui indique les navigateurs à prendre en charge (ici Chrome 40, sorti en 2015) dans un fichier
babel.config.json:
- Babel est un transpileur de JavaScript vers JavaScript. On lui indique les navigateurs à prendre en charge (ici Chrome 40, sorti en 2015) dans un fichier
{ "presets": [["@babel/preset-env", { "targets": "chrome 40" }]] }
npm install -D @babel/core @babel/cli @babel/preset-env
npx babel panier.js -o panier.es5.js

- Les deux versions affichent le même résultat :
Facture de Amel : 18.000 DT. Babel est utilisé par de nombreux outils de construction de sites (bundlers) ; on n'a besoin d'ES5 que pour de très anciens navigateurs.
-
Vérifier ou seulement traduire ?
- D'autres outils, beaucoup plus rapides que tsc, savent traduire du TypeScript en JavaScript : esbuild, SWC (utilisés notamment par Vite). Mais ils se contentent d'effacer les types, sans les vérifier.


- Dans un vrai projet, on combine souvent les deux : l'outil rapide produit le code pendant le développement, et
npx tsc --noEmit(vérifier sans produire de fichier) contrôle les types, par exemple avant chaque mise en ligne.
-
Un projet TypeScript pour le navigateur
- Dans un vrai projet, on ne compile pas les fichiers un par un : on décrit le projet dans un fichier
tsconfig.json, créé avecnpx tsc --initpuis adapté :
- Dans un vrai projet, on ne compile pas les fichiers un par un : on décrit le projet dans un fichier
{
"compilerOptions": {
"target": "es2022",
"lib": ["es2022", "dom"],
"strict": true,
"rootDir": "src",
"outDir": "dist",
"sourceMap": true,
"noEmitOnError": true
},
"include": ["src"]
}

- Le code source est dans
src/app.ts: une petite calculatrice de moyenne qui lit un champ de saisie.
// src/app.ts : calcul d'une moyenne dans le navigateur
const champ = document.querySelector<HTMLInputElement>("#notes");
const bouton = document.querySelector<HTMLButtonElement>("#calculer");
const resultat = document.querySelector<HTMLParagraphElement>("#resultat");
function lireNotes(texte: string): number[] {
return texte
.split(",")
.map((morceau) => Number(morceau.trim()))
.filter((n) => !Number.isNaN(n) && n >= 0 && n <= 20);
}
function moyenne(notes: number[]): number | null {
if (notes.length === 0) return null;
return notes.reduce((somme, n) => somme + n, 0) / notes.length;
}
bouton?.addEventListener("click", () => {
if (!champ || !resultat) return;
const notes = lireNotes(champ.value);
const m = moyenne(notes);
resultat.textContent = m === null
? "Saisissez des notes entre 0 et 20, séparées par des virgules."
: `Moyenne de ${notes.length} note(s) : ${m.toFixed(2)} / 20`;
});
projet/
├── index.html
├── tsconfig.json
├── src/
│ └── app.ts
└── dist/ ← créé par npx tsc
├── app.js
└── app.js.map
querySelector<HTMLInputElement>précise le type d'élément attendu : TypeScript sait alors qu'il possède une propriétévalue.bouton?.addEventListeneretif (!champ || !resultat) return;traitent le cas où l'élément n'existe pas dans la page (querySelectorrenvoie alorsnull).

- Sans ces précautions, tsc refuse le code. Le fichier
dom.tsci-dessous oublie les deux :
// dom.ts : TypeScript connaît le DOM du navigateur
const champ = document.querySelector("#notes");
console.log(champ.value);

- La page HTML charge le fichier JavaScript produit, jamais le
.ts:
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Moyenne – TypeScript dans le navigateur</title>
<style>
body { font-family: system-ui, sans-serif; max-width: 520px; margin: 40px auto; padding: 0 16px; }
input { width: 100%; padding: 10px; font-size: 16px; box-sizing: border-box; }
button { margin-top: 10px; padding: 10px 18px; font-size: 16px; background: #3178c6; color: #fff; border: 0; border-radius: 6px; cursor: pointer; }
#resultat { font-size: 18px; font-weight: bold; color: #1e293b; }
</style>
</head>
<body>
<h1>Calcul de moyenne</h1>
<label for="notes">Notes, séparées par des virgules :</label>
<input id="notes" value="12, 15, 9, 17">
<button id="calculer">Calculer</button>
<p id="resultat"></p>
<!-- Le navigateur charge le JavaScript produit par tsc, jamais le fichier .ts -->
<script src="dist/app.js"></script>
</body>
</html>

-
Erreur classique : charger le .ts dans la page
- Que se passe-t-il si l'on écrit
<script src="src/app.ts">? Selon le serveur, deux erreurs réelles apparaissent dans la console (F12) :
- Que se passe-t-il si l'on écrit

-
Les source maps
- Avec l'option
sourceMap, tsc produit à côté deapp.jsun fichierapp.js.map. Grâce à lui, les outils de développement du navigateur (et Node.js) affichent les erreurs et les points d'arrêt dans le fichier .ts, alors que c'est le .js qui s'exécute.
- Avec l'option

-
Avantages et limites des langages transpilés
- Transpiler ajoute une étape au développement, mais apporte beaucoup sur un projet de taille moyenne ou grande :

- Pour un petit script de quelques lignes, JavaScript seul suffit. Dès que le projet grandit, ou qu'on travaille à plusieurs, TypeScript devient très utile : c'est pourquoi la plupart des frameworks récents l'utilisent.
- Dans ce cours, nous continuerons à écrire du JavaScript: c'est le langage que le navigateur exécute, et tout ce que vous apprenez reste vrai en TypeScript.

-
Activité 1 : compiler ou transpiler ?
- Pour chaque opération, dites s'il s'agit d'une compilation vers du code machine, d'une transpilation vers un autre langage, ou d'une transpilation « de version » (JavaScript vers JavaScript) :
gcc programme.c -o programmenpx tsc app.tsnpx babel app.js -o app.es5.jsnpx coffee -c notes.coffeedart compile js main.dartrustc main.rsnpx tsc --target es2015 moderne.ts
- Pour chaque cas transpilé, indiquez aussi la famille du langage source (sur-ensemble typé, syntaxe alternative, autre langage, JS récent).
- Pour chaque opération, dites s'il s'agit d'une compilation vers du code machine, d'une transpilation vers un autre langage, ou d'une transpilation « de version » (JavaScript vers JavaScript) :
-
Activité 2 : corriger les erreurs de TypeScript
- Récupérez le fichier
erreurs.tsde la leçon (dossierexemples/). - Lancez
npx tsc --noEmitOnError erreurs.tset lisez les cinq messages : pour chacun, notez la ligne et expliquez l'erreur avec vos mots. - Corrigez le fichier jusqu'à ce que tsc n'affiche plus rien, sans supprimer de ligne : l'élève Sana restant introuvable, le programme doit afficher « élève introuvable ».
- Exécutez le fichier
erreurs.jsproduit.
- Récupérez le fichier
-
Activité 3 : typer un panier
- Créez
panier.tsavec :- une interface
Article:produit(texte),prixetquantite(nombres), et uneremiseen pourcentage facultative (remise?: number) ; - une fonction
sousTotal(a: Article): numberqui applique la remise si elle existe ; - une fonction
total(panier: Article[]): number; - un panier de trois articles, dont un stylo à 0,800 DT × 10 avec 25 % de remise, et l'affichage de chaque sous-total puis du total.
- une interface
- Ajoutez ensuite un article avec
prix: "1.2", puis un article sans prix : quels messages tsc affiche-t-il ?
- Créez
-
Activité 4 : prévoir le JavaScript produit
- On donne le fichier
salut.js:
- On donne le fichier
// Activité 4 : que deviennent ces lignes ?
const saluer = (nom = "élève") => `Bonjour ${nom} !`;
const { ville } = { ville: "Sousse" };
console.log(saluer(), saluer("Amel"), ville);
- Sans lancer d'outil, écrivez ce que produira Babel avec la cible Chrome 40 (ES5) : que deviennent
const, la fonction fléchée, le paramètre par défaut, le gabarit et la déstructuration ? - Que produira
tsc --target es2015sur le même code (renommé en.ts) ? Justifiez. - Vérifiez vos réponses avec les deux outils, puis exécutez les trois versions : affichent-elles la même chose ?
-
Activité 5 : un projet avec tsconfig.json et source maps
- Créez un dossier avec un fichier
src/conversion.tsqui convertit en degrés Fahrenheit les températures[0, 21.5, 37, 100](formule : °F = °C × 9 / 5 + 32), puis déclenche volontairement une erreur :throw new Error("Capteur débranché"); - Écrivez un
tsconfig.json: cible ES2022, sources danssrc, sortie dansdist, mode strict, source maps, aucune sortie en cas d'erreur. - Compilez avec
npx tsc: quels fichiers apparaissent dansdist? Que contient la dernière ligne deconversion.js? - Exécutez
node dist/conversion.js, puisnode --enable-source-maps dist/conversion.js: quel fichier et quelle ligne l'erreur indique-t-elle dans chaque cas ?
- Créez un dossier avec un fichier
-
Activité 6 : vérifier des données à l'exécution
- Le fichier
notes.jsonvient d'une autre application :
- Le fichier
[
{ "nom": "Amel", "note": 15 },
{ "nom": "Karim", "note": "14" },
{ "nom": "Sana" },
{ "nom": "Youssef", "note": 11.5 }
]
- Expliquez pourquoi l'interface
Elevene suffit pas à protéger le programme contre ces données. - Écrivez une fonction
estEleve(x: unknown): x is Eleve(une « garde de type ») qui vérifie qu'un objet a unnomde type texte et unenotenumérique entre 0 et 20. - Lisez le fichier, ignorez les élèves invalides en les affichant, puis calculez la moyenne des élèves valides. Exécutez votre programme avec
node lecture.ts.
-
Activité 7 : convertir un script JavaScript en TypeScript
- On donne un compteur de caractères pour SMS (limite de 160 caractères), écrit en JavaScript :
// compteur-depart.js : le script JavaScript à convertir en TypeScript
const zone = document.querySelector("#message");
const info = document.querySelector("#info");
const LIMITE = 160;
function compter(texte) {
return texte.length;
}
zone.addEventListener("input", () => {
const n = compter(zone.value);
info.textContent = n + " / " + LIMITE + " caractères";
info.style.color = n > LIMITE ? "crimson" : "green";
});
- Copiez-le dans
src/compteur.tset lancez tsc avec la bibliothèquedom: combien d'erreurs obtenez-vous, et de quels types ? - Corrigez le code : types d'éléments avec
querySelector<…>, casnull, paramètre typé. Ajoutez l'affichage du nombre de caractères en trop. - Créez le
tsconfig.jsonet la pageindex.htmlqui chargedist/compteur.js, puis testez dans le navigateur.

- Les corrigés des sept activités sont fournis dans l'archive de la leçon (dossier
corriges/) : un document de correction et les fichiers corrigés, tous compilés et testés.
-
Erreurs fréquentes
| Erreur | Ce qui se passe | Solution |
|---|---|---|
<script src="app.ts"> |
MIME 'video/mp2t' refusé, ou SyntaxError: Unexpected token ':' |
Charger le fichier produit : dist/app.js |
| Croire que les types protègent à l'exécution | Des données JSON ou saisies invalides passent sans contrôle | Vérifier les données externes avec du code (garde de type) |
| Ignorer les erreurs de tsc | Le .js est produit quand même, le programme plante plus tard | Activer noEmitOnError |
| Compter sur esbuild, Vite ou Node.js pour vérifier | Ils effacent les types sans les contrôler | Lancer npx tsc --noEmit |
npx tsc fichier.ts dans un projet qui a un tsconfig.json |
Erreur TS5112 : le fichier tsconfig est ignoré | Lancer npx tsc seul |
--target es5 avec TypeScript 7 |
Erreur TS5108 : option supprimée | Cible ES2015 au minimum, ou Babel pour ES5 |
Un enum exécuté avec node fichier.ts |
ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX | Compiler avec tsc, ou utiliser un objet constant |
document.querySelector("#x").value |
TS18047 (possibly null) et TS2339 (pas de value sur Element) | querySelector<HTMLInputElement> et tester null |
| Modifier le fichier .js produit | Les changements sont écrasés à la compilation suivante | Toujours modifier le .ts, puis recompiler (npx tsc --watch) |
-
À retenir
- Le navigateur n'exécute que du JavaScript : un langage transpilé est traduit en JavaScript avant d'être exécuté.
- Transpiler, c'est compiler d'un langage de haut niveau vers un autre (ou vers une autre version du même langage).
- Quatre familles : sur-ensembles typés (TypeScript), syntaxes alternatives (CoffeeScript), autres langages (Dart, Elm), JavaScript récent vers ancien (Babel).
- TypeScript = JavaScript + types.
tscvérifie le code et produit du JavaScript ; les types sont effacés à l'exécution. - esbuild, SWC, Babel et Node.js traduisent sans vérifier les types :
tsc --noEmitreste nécessaire. - Un projet se configure dans
tsconfig.json(target, lib, strict, outDir, sourceMap, noEmitOnError) ; la page charge le.jsproduit.
Un langage transpilé ne remplace pas JavaScript : il l'enrichit pendant le développement, puis s'efface. Bien connaître JavaScript reste indispensable.