Vous contraignez vos paramètres de type avec extends et fournissez des valeurs par défaut pour des API génériques ergonomiques.
Ouvrir cette leçon dans KodokonUn générique sans contrainte est opaque : dans le corps de la fonction, T ne vous autorise rien. La clause extends établit un contrat minimal sur le paramètre de type, ce qui débloque l'accès aux propriétés garanties tout en préservant le type précis de l'appelant. C'est la différence fondamentale avec un paramètre typé par une interface : la contrainte conserve l'information, l'interface l'efface.
function longest<T extends { length: number }>(
a: T,
b: T
): T {
return a.length >= b.length ? a : b;
}
const word = longest("hello", "worldwide");
const list = longest([1, 2], [3, 4, 5]);Le duo K extends keyof T est le pattern le plus rentable du quotidien : il lie deux paramètres de type entre eux et garantit statiquement qu'une clé appartient bien à l'objet. Le type de retour T[K] (un type indexé) suit précisément la propriété demandée. C'est exactement ainsi que sont typées les fonctions comme pick ou pluck des bibliothèques utilitaires.
function getProp<T extends object, K extends keyof T>(
obj: T,
key: K
): T[K] {
return obj[key];
}
const config = { port: 8080, host: "localhost" };
const port = getProp(config, "port");
const host = getProp(config, "host");Les valeurs par défaut (T = string) rendent un générique optionnel à l'appel : l'utilisateur ne fournit l'argument de type que lorsqu'il veut dévier du cas courant. Combinées à une contrainte (T extends X = Y), elles définissent à la fois la borne et le comportement implicite. Le défaut doit satisfaire la contrainte, sinon la déclaration elle-même ne compile pas. C'est le pattern standard des clients HTTP, des stores et des event emitters typés.
interface ApiResponse<T = unknown> {
status: number;
data: T;
}
async function fetchJson<T = unknown>(
url: string
): Promise<ApiResponse<T>> {
const res = await fetch(url);
return { status: res.status, data: await res.json() };
}
interface Post { id: number; title: string }
const typed = await fetchJson<Post>("/api/posts/1");
const loose = await fetchJson("/api/health");K extends keyof T dans une signature générique ?longest<T extends { length: number }> a-t-il sur longest(a: { length: number }, b: ...) sans générique ?<T = unknown> à <T = any> comme valeur par défaut ?