JavaScript est typé dynamiquement, ce qui est vraiment utile — vous pouvez itérer rapidement, prototyper librement et déployer sans étape de compilation. Mais cette flexibilité a un coût : toute une classe d'erreurs ne se manifeste qu'à l'exécution. Une fonction attend une chaîne, reçoit undefined, et votre application plante en production à 2h du matin. TypeScript
ajoute un système de types statiques par-dessus JavaScript qui détecte exactement ces erreurs au moment de la compilation, dans votre éditeur, avant que quoi que ce soit ne soit déployé. Cet article explique ce que cela signifie concrètement — avec du vrai code, des compromis honnêtes, et sans tapage.
Ce qu'est réellement TypeScript
TypeScript est un sur-ensemble de JavaScript : chaque fichier .js valide est aussi un fichier .ts valide.
Vous pouvez renommer un fichier, n'ajouter aucune annotation de type, et il compile sans problème. Ce que TypeScript
ajoute — annotations de types, interfaces, génériques, enums — est entièrement supprimé à la compilation. Le
résultat est du JavaScript ordinaire. TypeScript ne change pas ce qui s'exécute ; il change ce que vous pouvez savoir
avant l'exécution.
Le compilateur est tsc, installé via
npm. Vous le pointez sur vos
fichiers .ts et il produit des fichiers .js que votre runtime (Node.js, un navigateur, Deno)
peut exécuter. Aucune syntaxe spécifique à TypeScript n'atteint jamais la production — les types n'existent que pour
le développeur et la chaîne d'outils. Le
dépôt TypeScript sur GitHub
est lui-même un grand projet TypeScript, ce qui vous donne une idée de son passage à l'échelle.
# Compile a single file
npx tsc src/index.ts
# Compile a whole project (uses tsconfig.json)
npx tsc
# Watch mode — recompile on every save
npx tsc --watchLe bénéfice principal : les erreurs avant l'exécution
Voici le problème que TypeScript résout le plus visiblement. Imaginez que vous travaillez avec une réponse d'API
où un champ pourrait être une chaîne ou null. En JavaScript ordinaire, cela échoue silencieusement en
production :
// JavaScript — no error until this actually runs with a null value
function formatDisplayName(user) {
return user.displayName.toUpperCase(); // 💥 TypeError if displayName is null
}
// This looks fine in isolation. The bug only appears when a user
// has no display name set — which might be rare, but it will happen.
const name = formatDisplayName({ displayName: null });TypeScript détecte cela avant l'exécution du code :
interface User {
id: number;
displayName: string | null;
email: string;
}
function formatDisplayName(user: User): string {
return user.displayName.toUpperCase();
// ❌ TypeScript error: Object is possibly 'null'.
// Property 'toUpperCase' does not exist on type 'null'.
}
// Fix: handle the null case explicitly
function formatDisplayName(user: User): string {
if (user.displayName === null) {
return user.email; // fall back to email
}
return user.displayName.toUpperCase(); // TypeScript now knows this is safe
}C'est le moment « aha » pour la plupart des développeurs. Le message d'erreur vous indique exactement ce qui ne va pas
et où — dans votre éditeur, avant d'exécuter une seule ligne. Avec le mode strict activé, TypeScript
est particulièrement agressif pour détecter les problèmes null et undefined via sa
fonctionnalité strictNullChecks,
activée par défaut en mode strict.
tsc signifie que votre code a une incohérence de type — TypeScript peut prouver qu'il va
échouer (ou pourrait échouer) sans l'exécuter. Corrigez l'erreur de type, et vous aurez éliminé toute la classe de bogues.Le système de types TypeScript en un coup d'œil
Vous n'avez pas besoin d'annoter tout. TypeScript infère les types à partir des affectations, des valeurs de retour, et des appels de fonctions — souvent vous écrivez juste du JavaScript normal et obtenez la vérification de type gratuitement. Mais connaître la syntaxe d'annotation aide quand l'inférence ne suffit pas.
// Primitives
const productName: string = 'Wireless Keyboard';
const price: number = 79.99;
const inStock: boolean = true;
// TypeScript infers these without annotations — same effect
const productName = 'Wireless Keyboard'; // inferred: string
const price = 79.99; // inferred: number
// Arrays
const tags: string[] = ['electronics', 'peripherals'];
const ratings: number[] = [4.5, 4.8, 4.2];
// Objects with interfaces
interface Product {
id: number;
name: string;
price: number;
category: string;
inStock: boolean;
description: string | null; // union type — string or null
}
// Union types — a value that could be one of several types
type Status = 'active' | 'inactive' | 'pending'; // string literal union
type ID = string | number; // string or number
// Function with typed parameters and return type
function formatProductCard(product: Product): string {
const stockLabel = product.inStock ? 'In Stock' : 'Out of Stock';
const desc = product.description ?? 'No description available';
return `${product.name} — $${product.price.toFixed(2)} (${stockLabel})
${desc}`;
}
// Generic function — works with any type, preserves it
function firstOrDefault<T>(items: T[], fallback: T): T {
return items.length > 0 ? items[0] : fallback;
}
const first = firstOrDefault(['a', 'b', 'c'], 'z'); // inferred: string
const num = firstOrDefault([1, 2, 3], 0); // inferred: numberLe manuel TypeScript approfondit le système de types — il est vraiment bien écrit et vaut la peine d'être lu une fois que vous avez les bases.
Configurer TypeScript dans un projet
Ajouter TypeScript à un projet prend environ cinq minutes. Vous installez le compilateur comme dépendance de développement,
générez un fichier de configuration et commencez à renommer les fichiers .js en .ts au
rythme qui convient.
# Install TypeScript as a dev dependency
npm install -D typescript
# Generate tsconfig.json with sensible defaults
npx tsc --initLe tsconfig.json généré contient des dizaines d'options, la plupart commentées. Les principales
à connaître :
{
"compilerOptions": {
"target": "ES2020", // what JavaScript version to output
"module": "commonjs", // module system (commonjs for Node, ESNext for bundlers)
"outDir": "./dist", // where compiled .js files go
"rootDir": "./src", // where your .ts source files live
"strict": true, // enables all strict type checks — highly recommended
"esModuleInterop": true, // smoother interop with CommonJS modules
"skipLibCheck": true // skip type checks on .d.ts files in node_modules
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}Activez toujours strict: true sur un nouveau projet. Cela regroupe plusieurs
vérifications dont strictNullChecks, noImplicitAny et
strictFunctionTypes. Sur une base de code existante, vous devrez peut-être les activer progressivement —
mais pour tout ce qui est en greenfield, commencez strict.
TypeScript vs JavaScript — les vrais compromis
TypeScript présente de nombreux avantages réels, mais aussi de vrais coûts. Voici un bilan honnête :
- Autocomplétion qui fonctionne vraiment. Votre éditeur connaît la forme de chaque objet, il peut donc suggérer les bons noms de propriétés et signatures de méthodes au lieu de deviner. Cela seul fait gagner du temps chaque jour.
- Bogues détectés avant d'atteindre la production. Déréférences null, types d'arguments erronés, propriétés requises manquantes — TypeScript les signale à l'écriture, pas à 3h dans un canal d'incident.
- Refactorisation plus sûre. Renommez un champ dans une interface et TypeScript signale immédiatement tous les appels qui nécessitent une mise à jour. Dans une grande base de code JavaScript, ce genre de modification est terrifiant.
- Le code se documente lui-même. Une signature de fonction comme
sendEmail(to: string, subject: string, body: string, options?: EmailOptions): Promise<SendResult>vous dit tout ce que vous devez savoir sans lire l'implémentation. - Meilleur pour les équipes. Quand plusieurs développeurs partagent une base de code, les types forment un contrat entre les modules. Vous pouvez refactoriser votre code sans casser celui de votre collègue.
Et les coûts honnêtes :
- Ça ajoute une étape de compilation. Pour un petit script ou un prototype rapide, exécuter
tscavant de pouvoir tester est une vraie friction. Le JavaScript vanilla s'exécute immédiatement. - La configuration initiale prend du temps. Configurer
tsconfig.json, ajouter des définitions de types pour les bibliothèques tierces (@types/express, etc.) et configurer votre éditeur correctement prend quelques heures de travail. anycompromet tout le dispositif. TypeScript a une échappatoire — vous pouvez typer n'importe quoi commeany, ce qui désactive la vérification de type pour cette valeur. Une utilisation excessive d'anysignifie que vous avez la friction de TypeScript sans la sécurité. C'est une béquille, pas une solution.- Les types de bibliothèques tierces peuvent prendre du retard. Tous les packages npm ne fournissent pas des définitions TypeScript.
Certains s'appuient sur des packages
@types/*maintenus par la communauté qui peuvent être incomplets ou obsolètes.
Là où TypeScript brille vraiment
TypeScript offre les meilleurs rendements dans trois situations : les grandes bases de code, les bibliothèques partagées, et tout ce qui sera refactorisé avec le temps. Le système de types agit comme une documentation vivante toujours à jour — contrairement aux commentaires ou aux fichiers README.
Un exemple pratique : votre application appelle une API REST qui retourne des données utilisateur. Sans TypeScript, vous faites confiance à l'API pour retourner ce que vous attendez. Avec TypeScript, vous modélisez la réponse et obtenez un retour immédiat si quelque chose ne correspond pas :
interface ApiUser {
id: number;
username: string;
email: string;
avatarUrl: string | null;
createdAt: string; // ISO 8601 date string
role: 'admin' | 'editor' | 'viewer';
}
interface ApiResponse<T> {
data: T;
total: number;
page: number;
perPage: number;
}
async function fetchUsers(page: number): Promise<ApiResponse<ApiUser[]>> {
const response = await fetch(`/api/users?page=${page}`);
if (!response.ok) {
throw new Error(`Failed to fetch users: ${response.status}`);
}
return response.json() as Promise<ApiResponse<ApiUser[]>>;
}
// Now every consumer of this function knows exactly what they'll get
const result = await fetchUsers(1);
result.data.forEach(user => {
// TypeScript knows user.role is 'admin' | 'editor' | 'viewer'
// It will error if you try to access a property that doesn't exist
console.log(`${user.username} (${user.role})`);
});Quand vous devez temporairement désactiver la vérification de type, utilisez unknown plutôt que
any. La différence : any contourne silencieusement toutes les vérifications, tandis qu'unknown
vous oblige à affiner le type avant d'utiliser la valeur — vous obtenez l'échappatoire sans perdre entièrement la sécurité.
// ❌ any — TypeScript trusts you completely, no checks
function processData(data: any) {
data.nonExistentMethod(); // no error — TypeScript looks away
}
// ✅ unknown — you have to prove what it is before using it
function processData(data: unknown) {
if (typeof data === 'string') {
console.log(data.toUpperCase()); // safe — TypeScript knows it's a string here
} else if (Array.isArray(data)) {
console.log(data.length); // safe — TypeScript knows it's an array
}
}Le Playground TypeScript est la façon la plus rapide d'expérimenter avec ces patrons. Collez du code, voyez la sortie JavaScript compilée et les éventuelles erreurs de type en temps réel — aucune installation requise.
Conclusion
TypeScript n'est pas magique, et ce n'est pas adapté à tous les projets. Mais pour toute base de code JavaScript qui grandit, est maintenue par plus d'une personne, ou sera refactorisée — il change vraiment l'expérience de développement. Le système de types détecte toute une catégorie de bogues d'exécution avant qu'ils ne soient déployés, rend l'autocomplétion vraiment utile, et transforme la refactorisation d'un processus manuel risqué en quelque chose que la chaîne d'outils gère.
Commencez avec la documentation officielle TypeScript — elle est bien structurée et adaptée aux débutants. Le Playground TypeScript est idéal pour expérimenter sans aucune configuration. L' entrée glossaire TypeScript de MDN est un bon aperçu en une page si vous voulez une autre perspective. Et si vous travaillez avec des données JSON en TypeScript, l'outil JSON vers TypeScript sur ce site génère des interfaces TypeScript directement depuis n'importe quelle charge utile JSON — utile quand vous devez modéliser une réponse API rapidement sans écrire les types à la main.