Langage de programmation

TypeScript

TypeScript ajoute des types statiques à JavaScript, permettant de détecter les bugs avant qu'ils n'atteignent la production. Voici ce que c'est, comment cela fonctionne et comment commencer à l'utiliser dès aujourd'hui.

beginner20 min readUpdated 15 sept. 2026
typescript
function greet(name: string): string {
  return `Hello, ${name}!`;
}

const message = greet("TypeScript");
console.log(message);
Créé
2012, par Microsoft
Type
Sur-ensemble typé statiquement de JavaScript
Compile vers
JavaScript pur
Standard
ECMAScript avec extensions de types
Extension de fichier
.ts / .tsx
Version actuelle
TypeScript 5.x

Pourquoi c'est important

Pourquoi TypeScript est essentiel

Détecter les bugs tôt

Les erreurs de type sont détectées à la compilation, et non en production. Vous trouvez les erreurs avant même que votre code ne s'exécute.

Meilleure expérience éditeur

L'autocomplétion, la documentation en ligne et les outils de refactorisation fonctionnent car l'éditeur comprend la structure de votre code.

Code auto-documenté

Les types décrivent ce que les fonctions attendent et retournent. La lecture de la signature vous indique exactement comment l'utiliser.

Le tableau complet

Les trois piliers de TypeScript

TypeScript est à la fois un langage, un compilateur et un système de types. Comprendre dans quelle couche vous travaillez rend le débogage beaucoup plus simple.

TypeScript

Le langage

JavaScript plus des annotations de type, des interfaces, des génériques et des opérations de type avancées.

Le compilateur

tsc

Convertit TypeScript en JavaScript, vérifie les types et génère un code propre pour n'importe quelle cible.

L'écosystème

Outils & bibliothèques

Support IDE, fichiers de déclaration, mode strict et frameworks avec TypeScript intégré.

TypeScript en un coup d'œil

Ce que le langage vous apporte

Types primitifs

string, number, boolean, null, undefined, symbol, bigint.

Types d'objets

Interfaces, alias de type, classes et tableaux.

Unions & intersections

Combinez des types avec | (ou) et & (et) pour modéliser des données flexibles.

Type narrowing

Utilisez typeof, in et des discriminants pour permettre à TypeScript d'affiner les types à l'intérieur des conditionnels.

Génériques

Écrivez des fonctions et des types réutilisables qui fonctionnent avec n'importe quel type tout en restant type-safe.

Utility types

Transformations intégrées comme Partial, Pick et Record qui modifient des types existants.

Un bref aperçu

Des annotations optionnelles au standard de l'industrie

  1. 2012

    Lancement de TypeScript

    Microsoft publie TypeScript comme une couche de type optionnelle pour JavaScript.

    12
  2. 2016

    Angular mise sur TypeScript

    Angular adopte TypeScript comme langage principal, boostant son adoption dans tout l'écosystème.

    16
  3. 2018

    TypeScript 3.0

    Les références de projet, le type unknown et les tuples rendent le langage plus puissant.

    18
  4. 2020

    Tuples variadiques

    TypeScript 4.0 apporte les types de tuples variadiques et les éléments de tuple étiquetés.

    20
  5. 2023

    Standardisation des décorateurs

    Les décorateurs TC39 arrivent dans TypeScript 5.0, s'alignant sur la proposition ECMAScript.

    23
  6. Aujourd'hui

    Le choix par défaut

    La plupart des nouveaux projets JavaScript commencent avec TypeScript. Les frameworks l'intègrent nativement.

    Aujourd'hui

Le guide complet

TypeScript: Tout ce que vous devez savoir

Qu’est-ce que TypeScript ?

TypeScript est un superset de JavaScript à typage statique qui ajoute des annotations de type optionnelles vérifiées lors de la compilation. Il est compilé en JavaScript pur, ce qui lui permet de s’exécuter partout où JavaScript fonctionne : dans les navigateurs, Node.js, Deno et Bun.

Créé par Microsoft en 2012, TypeScript est devenu le choix par défaut pour les projets JavaScript sérieux. La raison est simple : il détecte les bugs avant même que votre code ne soit exécuté. Une faute de frappe dans le nom d’une propriété, un argument manquant, un type de retour incorrect — TypeScript signale ces erreurs à la compilation au lieu de les laisser provoquer des plantages en production.

La meilleure façon de concevoir TypeScript est de le voir comme du JavaScript avec un filet de sécurité. Vous écrivez le même langage que vous connaissez déjà, mais vous pouvez décrire la structure de vos données et les contrats de vos fonctions. Le compilateur vérifie que tout concorde, puis supprime les types pour ne laisser que du JavaScript propre.

Pourquoi TypeScript est essentiel

JavaScript est un langage à typage dynamique, ce qui signifie que vous pouvez passer n’importe quelle valeur à n’importe quelle fonction, et l’erreur n’apparaît que lorsque le code est réellement exécuté. Pour un petit script, cela ne pose pas de problème. Mais dans une application d’envergure avec des dizaines de développeurs, c’est la recette idéale pour générer des bugs en production.

TypeScript résout ce problème en vérifiant les types avant l’exécution du code :

  • Détection des bugs à la compilation — une faute de frappe dans une propriété, un mauvais type d’argument ou l’oubli de la gestion d’une valeur null, et TypeScript vous avertit immédiatement.
  • Meilleure expérience dans l’éditeur — l’autocomplétion fonctionne car l’éditeur connaît les propriétés d’un objet. Le refactoring est sécurisé car le compilateur identifie chaque endroit nécessitant une mise à jour.
  • Code auto-documenté — les signatures des fonctions décrivent exactement ce qu’elles attendent et ce qu’elles retournent. La lecture des types vous indique comment utiliser le code sans avoir à en lire l’implémentation.
  • Refactoring plus sûr — modifiez un type et le compilateur mettra en évidence tous les endroits qui sont impactés. Plus besoin de fouiller dans la base de code pour traquer des erreurs d’exécution.
  • Adoption progressive — vous pouvez ajouter TypeScript à un projet JavaScript existant de manière incrémentale, fichier par fichier.

TypeScript n’ajoute aucun overhead à l’exécution. Les types sont supprimés lors de la compilation, donc le JavaScript livré aux utilisateurs est identique, que vous l’ayez écrit en TypeScript ou non.

Comment fonctionne TypeScript

Le code TypeScript réside dans des fichiers .ts. Le compilateur TypeScript (tsc) lit ces fichiers, vérifie les types et génère des fichiers .js dont les annotations de type ont été supprimées.

// app.ts
function add(a: number, b: number): number {
  return a + b;
}

const result = add(1, 2); // result is number

Le compilateur vérifie que a et b sont des nombres, que la fonction retourne un nombre et que result reçoit un nombre. Si un élément ne correspond pas, vous obtenez une erreur à la compilation. Le JavaScript généré est simplement :

function add(a, b) {
  return a + b;
}
const result = add(1, 2);

Pas de types, pas de surcharge. La sécurité n’intervient que lors de l’étape de build.

Annotations de type

Les annotations de type décrivent le type d’une variable, d’un paramètre ou d’une valeur de retour :

// primitives
let name: string = "Ada";
let age: number = 36;
let active: boolean = true;

// arrays
let skills: string[] = ["HTML", "CSS"];
let scores: Array<number> = [95, 87, 92];

// function parameters and return
function greet(name: string): string {
  return `Hello, ${name}!`;
}

Les annotations ne sont pas toujours nécessaires. TypeScript infère les types à partir de la valeur :

let count = 0;          // inferred as number
const items = ["a"];    // inferred as string[]

Privilégiez l’inférence lorsque le type est évident. Utilisez les annotations lorsque le type n’est pas clair d’après la valeur, lorsque vous avez besoin d’un type plus général, ou lorsque l’inférence par défaut est trop restrictive.

Inférence de type

TypeScript déduit automatiquement les types à partir du contexte :

// from assignment
let x = 5; // number

// from return value
function doubling(n: number) {
  return n * 2; // inferred as number
}

// from context
const numbers = [1, 2, 3]; // number[]
const doubled = numbers.map(n => n * 2); // number[]

L’inférence vous permet d’écrire moins de code tout en conservant le même niveau de sécurité. La plupart du code TypeScript repose largement sur l’inférence — n’utilisez les annotations que lorsqu’elles apportent de la clarté.

Types d’union (Union types)

Un type d’union indique qu’une valeur peut être l’un parmi plusieurs types :

type Status = "loading" | "success" | "error";

function handleStatus(status: Status) {
  if (status === "loading") {
    // TypeScript knows status is "loading" here
  }
}

let value: string | number;
value = "hello";
value = 42;

Les unions modélisent très bien les données du monde réel. Les réponses d’une API peuvent réussir ou échouer. Un champ peut être une chaîne de caractères ou null. Une fonction peut accepter différents types d’entrées.

Le narrowing de type

TypeScript affine (narrowing) les types d’union à l’intérieur des conditionnels :

function process(value: string | number) {
  if (typeof value === "string") {
    // TypeScript knows value is string here
    return value.toUpperCase();
  }
  // TypeScript knows value is number here
  return value.toFixed(2);
}

Le narrowing fonctionne également avec :

  • l’opérateur in — pour vérifier si une propriété existe
  • instanceof — pour vérifier les instances de classe
  • les vérifications d’égalité — === et !==
  • les unions discriminées — pour vérifier une propriété de marquage (tag) commune
type Circle = { kind: "circle"; radius: number };
type Square = { kind: "square"; side: number };
type Shape = Circle | Square;

function area(shape: Shape) {
  switch (shape.kind) {
    case "circle":
      return Math.PI * shape.radius ** 2;
    case "square":
      return shape.side ** 2;
  }
}

Les unions discriminées sont l’un des patterns les plus puissants de TypeScript. La propriété kind indique précisément à TypeScript avec quelle variante vous travaillez.

Interfaces et alias de type

Une interface décrit la forme d’un objet — ses propriétés, leurs types et si elles sont obligatoires. Un alias de type donne un nom à n’importe quel type, y compris les unions, les tuples, les primitives et les types de fonctions.

// Interface
interface User {
  id: number;
  name: string;
  email: string;
}

// Type alias with the same shape
type User = {
  id: number;
  name: string;
  email: string;
};

Pour les formes d’objets simples, les deux sont interchangeables. Les différences apparaissent lorsque vous composez ou étendez des types.

Propriétés optionnelles et en lecture seule

interface User {
  id: number;
  name: string;
  email?: string;      // optional — string | undefined
  readonly createdAt: Date;
}

const user: User = { id: 1, name: "Ada", createdAt: new Date() };
user.createdAt = new Date(); // Error: cannot assign to a readonly property

Étendre les interfaces

Les interfaces héritent d’autres interfaces avec extends, y compris plusieurs à la fois :

interface Timestamped {
  createdAt: Date;
  updatedAt: Date;
}

interface User extends Timestamped {
  id: number;
  name: string;
}

Alias de type pour les unions, tuples et fonctions

Les alias de type sont particulièrement utiles lorsque le type n’est pas un objet simple :

type ID = string | number;
type Status = "idle" | "loading" | "success" | "error";
type Pair = [string, number];
type Callback = (data: unknown) => void;

Types d’intersection

Combinez des types avec & :

type User = { id: number; name: string };
type WithTimestamp = { createdAt: Date };

type TimestampedUser = User & WithTimestamp;

Interface ou type ?

Utilisez les interfaces pour les formes d’objets susceptibles d’être étendues ou implémentées par des classes. Utilisez les alias de type pour les unions, les intersections, les tuples et les types de fonctions. Choisissez une convention pour les formes d’objets et restez cohérent.

Les Génériques

Les génériques sont des paramètres de type : ils permettent à une fonction, une interface ou une classe de fonctionner avec n’importe quel type tout en préservant la sécurité du typage. Au lieu de coder un type en dur ou de se rabattre sur any, vous passez une variable de type qui est définie lors de l’appel.

function first<T>(items: T[]): T | undefined {
  return items[0];
}

const num = first([1, 2, 3]);    // number
const str = first(["a", "b"]);   // string

Sans les génériques, vous devriez soit utiliser any et perdre les informations de type, soit écrire une fonction distincte pour chaque type.

Fonctions génériques

Un paramètre de type est déclaré entre chevrons. TypeScript l’infère généralement à partir des arguments, vous n’avez donc que rarement besoin de le passer explicitement :

function merge<T, U>(a: T, b: U): T & U {
  return { ...a, ...b };
}

const result = merge({ name: "Ada" }, { age: 36 });
// { name: string; age: number }

Interfaces et classes génériques

interface Response<T> {
  data: T;
  status: number;
}

interface User {
  id: number;
  name: string;
}

const response: Response<User> = {
  data: { id: 1, name: "Ada" },
  status: 200,
};

class Stack<T> {
  private items: T[] = [];
  push(item: T) { this.items.push(item); }
  pop(): T | undefined { return this.items.pop(); }
}

Contraintes

Utilisez extends pour restreindre ce qu’un générique peut accepter :

interface HasId {
  id: number;
}

function findById<T extends HasId>(items: T[], id: number): T | undefined {
  return items.find((item) => item.id === id);
}

Paramètres de type par défaut

interface Paginated<T = unknown> {
  data: T[];
  total: number;
  page: number;
}

const response: Paginated = { data: [1, "a"], total: 10, page: 1 };

Les génériques sont supprimés lors de l’exécution (runtime), ils n’ajoutent donc aucun overhead — ils existent uniquement pour rendre le compilateur et votre éditeur plus intelligents.

Le fichier tsconfig.json

Le fichier tsconfig.json configure le compilateur TypeScript :

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "strict": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "esModuleInterop": true,
    "skipLibCheck": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

Options clés :

  • target — la version de JavaScript à générer (ES2020 est un bon choix par défaut)
  • strict — active tous les drapeaux de vérification de type stricte
  • module — le système de modules pour la sortie (ESNext pour les projets modernes)
  • outDir — le répertoire de destination du JavaScript compilé
  • esModuleInterop — permet les imports par défaut depuis des modules CommonJS

Utilisez toujours "strict": true pour les nouveaux projets. Cela permet de détecter plus de bugs, au prix d’un code légèrement plus explicite.

Installer TypeScript

# As a project dependency (recommended)
npm install --save-dev typescript

# Globally (not recommended for teams)
npm install -g typescript

Compilez votre projet :

# Using npx
npx tsc

# Or add a script to package.json
npm run build

Pour le développement avec le mode watch :

npx tsc --watch

La plupart des frameworks modernes (Next.js, Vite, Astro) gèrent la compilation TypeScript pour vous — vous n’avez pas besoin d’exécuter tsc manuellement.

Erreurs courantes

  • Utiliser any partout, ce qui désactive la vérification des types.
  • Annoter chaque élément alors que l’inférence connaît déjà le type.
  • Ne pas activer le mode strict dans le tsconfig.
  • Confondre les types TypeScript avec les valeurs au runtime — les types sont supprimés lors de la compilation.
  • Importer les types de manière incorrecte — utilisez import type pour les imports de types uniquement.
  • Ignorer les erreurs du compilateur au lieu de les corriger.
  • Ne pas installer les packages @types pour les bibliothèques JavaScript.
  • Rendre toutes les propriétés d’une interface optionnelles, ce qui masque les vérifications obligatoires.
  • Utiliser any au lieu d’un générique, perdant ainsi les informations de type que vous souhaitiez conserver.

Bonnes pratiques

  • Activez le mode strict dès le premier jour.
  • Laissez l’inférence faire le travail — n’ajoutez des annotations que lorsqu’elles apportent une valeur ajoutée.
  • Utilisez unknown au lieu de any lorsque vous ne connaissez pas le type.
  • Privilégiez les interfaces pour les formes d’objets susceptibles d’être étendues.
  • Utilisez les discriminated unions pour les machines à états et les données variantes.
  • Gardez les définitions de types proches de l’endroit où elles sont utilisées.
  • Utilisez import type pour les imports de types uniquement afin de réduire la taille du code au runtime.
  • Considérez le compilateur comme un coéquipier, et non comme un obstacle.

Quelle est la suite ?

Vous maîtrisez désormais les fondamentaux de TypeScript : annotations, inférence, unions, narrowing, interfaces, alias de type et génériques. La suite logique est de découvrir les Types Avancés pour apprendre les utility types, les types conditionnels et les mapped types. Choisissez un projet, refactorisez du code et laissez la pratique porter ses fruits.

Annotations de type

Les annotations explicites sont utiles quand le type n'est pas évident. Laissez l'inférence faire le travail quand c'est le cas.

Préférer
const count = 0;
const items: string[] = [];

function add(a: number, b: number) {
  return a + b;
}
Éviter
const count: number = 0;
const items: Array<string> = [];

function add(a: number, b: number): number {
  return a + b;
}

Utilisation de any

any désactive la vérification des types. Utilisez unknown quand vous ne connaissez pas le type, puis affinez-le.

Préférer
function parse(input: unknown) {
  if (typeof input === "string") {
    return input.toUpperCase();
  }
  return String(input);
}
Éviter
function parse(input: any) {
  return input.toUpperCase();
}

FAQ

Foire aux questions

Keep learning

Related topics from the roadmap.

$ commencer à apprendre

Prêt à apprendre TypeScript ?

Notre tutoriel interactif vous guide à travers TypeScript pas à pas — avec des quiz et du vrai code que vous pouvez exécuter dans le navigateur.