Programming Language

Types TypeScript Avancés

Les utility types, les conditional types et les mapped types vous permettent de transformer et de composer des types avec précision. Voici comment ils fonctionnent et quand les utiliser.

intermediate16 min readUpdated 15 sept. 2026
typescript
type Users = {
  ada: { age: 36 };
  bob: { age: 28 };
};

type UserNames = keyof Users;
type Ages = Users[UserNames];
Utility types
Transformations de types intégrées (Partial, Pick, Record)
Conditional types
T extends U ? X : Y
Mapped types
Transformation des propriétés d'un type existant
Template literals
Manipulation de chaînes au niveau du type
Mot-clé infer
Extraction de types à l'intérieur d'autres types
Conditionnels distributifs
Application de conditions à chaque membre d'une union

Pourquoi c'est important

Pourquoi les types avancés sont-ils importants

Transformation de types

Créez de nouveaux types à partir de types existants sans dupliquer les définitions. Modifiez, filtrez et remodelez les types pour répondre à vos besoins.

Contrats précis

Modélisez des données complexes avec des types exacts qui capturent les erreurs que d'autres ignorent. Unions discriminées, types exacts et branded types.

Moins de répétition

Dérivez les types automatiquement au lieu de maintenir des définitions parallèles. Une seule source de vérité, plusieurs types dérivés.

Le tableau complet

Les trois piliers de la transformation de types

Les utility types, les conditional types et les mapped types sont les outils qui vous permettent de construire n'importe quel type à partir de types existants sans vous répéter.

Utility types

Transformations intégrées

Partial, Required, Pick, Omit, Record, Extract, Exclude et d'autres types standards qui modifient des types existants.

Conditional types

Logique au niveau du type

Le if/else au niveau du type. T extends U ? X : Y vous permet de bifurquer les types en fonction de conditions.

Mapped types

Transformation de propriétés

Itérez sur les clés d'un type et transformez chaque propriété. C'est la base de la plupart des utility types.

Aperçu des types avancés

Ce que vous pouvez construire

Partial<T>

Rend toutes les propriétés optionnelles.

Required<T>

Rend toutes les propriétés obligatoires.

Pick<T, K>

Extrait un sous-ensemble de propriétés.

Omit<T, K>

Supprime des propriétés spécifiques.

Record<K, V>

Crée un type d'objet avec des clés K et des valeurs V.

Extract<U>

Extrait les membres d'une union qui correspondent à un type.

Un bref aperçu

Des alias simples à la programmation au niveau des types

  1. 2016

    Arrivée des utility types

    TypeScript 2.1 introduit les mapped types et des utilitaires intégrés comme Partial, Readonly et Pick.

    16
  2. 2018

    Lancement des conditional types

    TypeScript 2.8 ajoute les conditional types, permettant la logique au niveau du type et le mot-clé infer.

    18
  3. 2019

    Types récursifs

    TypeScript 4.1 active les conditional types récursifs et les template literal types.

    19
  4. 2021

    Template literal types

    La manipulation de chaînes au niveau du type ouvre de nouvelles possibilités pour la conception d'API.

    21
  5. 2023

    Opérateur satisfies

    TypeScript 4.9 ajoute satisfies pour valider des valeurs sans perdre les types littéraux.

    23
  6. Aujourd'hui

    Programmation au niveau du type

    Les types avancés sont essentiels pour les bibliothèques, les clients API et les états d'application complexes.

    Aujourd'hui

Le guide complet

Types TypeScript Avancés: Tout ce que vous devez savoir

Que sont les types avancés de TypeScript ?

Les types avancés sont des outils qui vous permettent de transformer, composer et manipuler des types au niveau du système de types. Au lieu de définir manuellement des types parallèles pour chaque variation, vous les dérivez automatiquement à partir de types existants.

Si les bases vous apportent les types et que les génériques vous permettent d’écrire du code réutilisable, les types avancés vous permettent de construire un système de types qui décrit vos données avec précision — capturant ainsi des erreurs que des approches plus simples laisseraient passer.

Les trois piliers sont les utility types (transformations intégrées), les conditional types (logique au niveau du type) et les mapped types (transformation de propriétés). Ensemble, ils forment un véritable petit langage pour travailler avec les types.

Types utilitaires

TypeScript propose des types intégrés permettant de modifier d’autres types :

Partial et Required

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

// All properties optional
type UserUpdate = Partial<User>;
// { id?: number; name?: string; email?: string; }

// All properties required
type StrictUser = Required<Partial<User>>;
// { id: number; name: string; email: string; }

Pick et Omit

// Extract specific properties
type UserPreview = Pick<User, "id" | "name">;
// { id: number; name: string; }

// Remove specific properties
type UserWithoutEmail = Omit<User, "email">;
// { id: number; name: string; }

Record

// Create object type with specific keys and values
type Scores = Record<string, number>;
// { [key: string]: number }

const scores: Scores = { math: 95, science: 87 };

// With union keys
type StatusMap = Record<"idle" | "loading" | "done", string>;

Extract et Exclude

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

// Keep only matching members
type ActiveStatus = Extract<Status, "loading" | "success">;
// "loading" | "success"

// Remove matching members
type InactiveStatus = Exclude<Status, "loading" | "success">;
// "idle" | "error"

ReturnType et Parameters

function createUser(name: string, age: number) {
  return { name, age, id: Date.now() };
}

type User = ReturnType<typeof createUser>;
// { name: string; age: number; id: number }

type Args = Parameters<typeof createUser>;
// [string, number]

NonNullable

type Maybe = string | null | undefined;
type Definite = NonNullable<Maybe>;
// string

Types mappés (Mapped types)

Les types mappés itèrent sur les clés d’un type existant pour transformer chaque propriété :

type ReadOnly<T> = {
  readonly [K in keyof T]: T[K];
};

type MutableUser = ReadOnly<User>;
// All properties are readonly

Ajout de modificateurs

// Add optional
type Optional<T> = {
  [K in keyof T]?: T[K];
};

// Remove optional
type Concrete<T> = {
  [K in keyof T]-?: T[K];
};

// Remove readonly
type Mutable<T> = {
  -readonly [K in keyof T]: T[K];
};

Les opérateurs - et + permettent de supprimer ou d’ajouter des modificateurs lors du mappage.

Remappage de clés avec as

TypeScript 4.1+ vous permet de remapper les clés pendant le mappage :

type Getters<T> = {
  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};

type UserGetters = Getters<User>;
// { getId: () => number; getName: () => string; getEmail: () => string; }

Types conditionnels

Les types conditionnels permettent d’exprimer une logique au niveau des types :

type IsString<T> = T extends string ? true : false;

type A = IsString<"hello">; // true
type B = IsString<42>;      // false

Le mot-clé infer

infer permet d’extraire un type à partir d’un autre type :

type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

type Fn = () => string;
type Result = ReturnType<Fn>; // string

Exemples pratiques

// Extract array element type
type ElementOf<T> = T extends (infer E)[] ? E : never;
type Num = ElementOf<number[]>; // number

// Unwrap promises
type Awaited<T> = T extends Promise<infer U> ? Awaited<U> : T;
type Deep = Awaited<Promise<Promise<string>>>; // string

// Extract object property types
type ValuesOf<T> = T[keyof T];
type UserValues = ValuesOf<User>; // number | string

Types conditionnels distributifs

Lorsqu’un type conditionnel est appliqué à une union, chaque membre de celle-ci est vérifié séparément :

type ToArray<T> = T extends any ? T[] : never;

type Result = ToArray<string | number>;
// string[] | number[] — not (string | number)[]

C’est particulièrement utile pour des types comme Extract et Exclude qui servent à filtrer les membres d’une union.

Les types Template Literal

Les types Template Literal permettent de manipuler des chaînes de caractères au niveau du typage :

type EventName<T extends string> = `on${Capitalize<T>}`;

type ClickEvent = EventName<"click">; // "onClick"
type FocusEvent = EventName<"focus">; // "onFocus"

Avec les mapped types

type EventHandlers<T extends string> = {
  [K in T as `on${Capitalize<K>}`]: () => void;
};

type MouseEvents = EventHandlers<"click" | "hover" | "focus">;
// { onClick: () => void; onHover: () => void; onFocus: () => void; }

Pattern matching de chaînes de caractères

type CSSProperty = `${string}-${string}`;
type ValidCSS = CSSProperty; // any string with a hyphen

Unions discriminées

Les unions discriminées sont le pattern avancé le plus important pour modéliser un état :

type RequestState<T> =
  | { status: "idle" }
  | { status: "loading" }
  | { status: "success"; data: T }
  | { status: "error"; error: string };

function handleState(state: RequestState<User>) {
  switch (state.status) {
    case "idle":
      return "Ready";
    case "loading":
      return "Loading...";
    case "success":
      return state.data.name; // TypeScript knows data exists
    case "error":
      return state.error;    // TypeScript knows error exists
  }
}

La propriété status est le discriminant. TypeScript affine le type automatiquement dans chaque branche.

Types brandés (Branded types)

Les types brandés permettent d’éviter de mélanger des types qui possèdent la même structure :

type UserId = string & { readonly __brand: unique symbol };
type OrderId = string & { readonly __brand: unique symbol };

function branded<T extends string>(value: T): T & { readonly __brand: unique symbol } {
  return value as any;
}

const userId = branded<UserId>("user-123");
const orderId = branded<OrderId>("order-456");

function getUser(id: UserId) { /* ... */ }
getUser(userId);  // OK
getUser(orderId); // Error: OrderId is not assignable to UserId

Bonnes pratiques

  • Utilisez des utility types plutôt que de dupliquer manuellement les définitions de types.
  • Privilégiez les discriminated unions aux type assertions pour la modélisation d’états.
  • Construisez vos types à partir de petits éléments composables plutôt que de définitions monolithiques volumineuses.
  • Utilisez les conditional types avec parcimonie — si un type est difficile à lire, simplifiez l’API.
  • Utilisez infer pour extraire les types des bibliothèques au lieu de typer manuellement les valeurs de retour.
  • Maintenez une source de vérité unique et dérivez tout le reste.
  • Utilisez des branded types lorsque vous avez besoin d’un typage nominal pour des IDs ou des valeurs similaires.
  • Considérez les types complexes comme un dernier recours — les types simples sont plus faciles à maintenir.

Erreurs courantes

  • Sur-concevoir les types alors que des solutions plus simples suffiraient.
  • Créer des types conditionnels profondément imbriqués et impossibles à déboguer.
  • Utiliser des assertions as au lieu d’un affinement de type (type narrowing) approprié.
  • Ne pas utiliser les types utilitaires, ce qui entraîne des duplications de définitions de types.
  • Rendre les types trop complexes par rapport au bénéfice qu’ils apportent.
  • Oublier que les types sont supprimés à l’exécution — il n’y a pas de vérification de type au runtime.
  • Ne pas documenter les types complexes avec des commentaires expliquant l’intention.

Quelle est la suite ?

Vous maîtrisez désormais les types avancés : les utility types, les types conditionnels, les mapped types et les template literals. La prochaine étape logique est de se plonger dans les fondamentaux de TypeScript — les annotations, l’inférence, les interfaces et les génériques. Choisissez un projet, refactorisez quelques types et laissez la pratique porter ses fruits.

Utility types vs définitions manuelles

Les utility types dérivent de types existants, maintenant une seule source de vérité. Les définitions manuelles créent des doublons et divergent.

Préférer
interface User {
  id: number;
  name: string;
  email: string;
}

type UserUpdate = Partial<User>;
type UserPreview = Pick<User, "id" | "name">;
Éviter
interface User {
  id: number;
  name: string;
  email: string;
}

interface UserUpdate {
  id?: number;
  name?: string;
  email?: string;
}

Unions discriminées vs assertions de type

Les unions discriminées donnent à TypeScript suffisamment d'informations pour affiner les types automatiquement.

Préférer
type Result =
  | { ok: true; data: User }
  | { ok: false; error: string };

function handle(result: Result) {
  if (result.ok) {
    console.log(result.data);
  }
}
Éviter
interface Result {
  ok: boolean;
  data?: User;
  error?: string;
}

function handle(result: Result) {
  const user = result.data as User;
}

FAQ

Foire aux questions

Keep learning

Related topics from the roadmap.

$ commencer à apprendre

Prêt à apprendre Advanced Types ?

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