Kodokon kodokon.com

Génériques : fonctions et types génériques simples

Écrivez des fonctions et des types réutilisables qui conservent la précision des types à chaque appel.

9 min · 3 questions

Ouvrir cette leçon dans Kodokon

Vous utilisez déjà des génériques sans le savoir : string[], Promise<number>... Il est temps d'en écrire. Un générique introduit un paramètre de type, une variable remplacée par un type concret à chaque utilisation. Objectif : écrire la logique une seule fois, sans sacrifier la précision des types.

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

const n = first([10, 20, 30]);
const s = first(["a", "b"]);
T est inféré : n est number | undefined, s est string | undefined

Notez que vous n'avez rien précisé à l'appel : TypeScript infère T depuis l'argument. Un générique sans contrainte accepte n'importe quoi ; or, une fonction a souvent besoin d'un minimum de garanties sur ses données. Le mot-clé extends impose une forme minimale à T.

TYPESCRIPT
interface HasId {
  id: number;
}

function findById<T extends HasId>(
  items: T[],
  id: number
): T | undefined {
  return items.find((item) => item.id === id);
}
Contrainte : T doit au moins posséder un id numérique

Les types eux-mêmes peuvent être génériques. C'est le quotidien du code réseau : la structure de la réponse est stable, seul le contenu de data varie. Un seul type décrit alors toutes vos réponses d'API.

TYPESCRIPT
interface ApiResponse<T> {
  ok: boolean;
  data: T;
}

type UserResponse = ApiResponse<{ name: string }>;

const res: UserResponse = {
  ok: true,
  data: { name: "Ada" },
};
Un type générique paramètre le contenu de data

Quiz de validation

Vérifiez que vous avez bien retenu les points clés de cette leçon.

  1. Dans function first<T>(items: T[]): T | undefined, que représente T ?
    • Un type concret défini une fois pour toutes
    • Un paramètre de type remplacé à chaque appel
    • Le type unknown
    • Un raccourci pour any
  2. Que garantit la contrainte <T extends HasId> ?
    • T est exactement le type HasId
    • T possède au minimum les propriétés de HasId
    • T hérite de la classe HasId
  3. Vous appelez first([10, 20, 30]) sans préciser de type. Que vaut T ?
    • any
    • unknown
    • number
    • 10 | 20 | 30