Exclude<T, U> est un type utilitaire introduit dans TypeScript pour soustraire un type d'un autre, lorsque certains valeurs doivent être exclues d'un type union.
Au départ, TypeScript ne proposait pas de méthode pratique pour soustraire un type d'un autre. Lors de la création d'API génériques et de refactorisations, il était souvent nécessaire d'obtenir un type "restant" — tout sauf les valeurs interdites. Plutôt que de manipuler manuellement les unions, il fallait maintenir plusieurs interfaces similaires.
Par exemple, lorsqu'il y a un type 'A | B | C', mais qu'il est nécessaire d'obtenir un type sans B. Cela est fréquemment requis lors de la construction de paramètres d'entrée complexes pour des fonctions, la filtration des valeurs autorisées et la formation dynamique des types.
Exclude résout ce problème. Sa signature simplifiée est la suivante :
type Exclude<T, U> = T extends U ? never : T;
Il retourne un type excluant de T tous les membres de U.
Exemple :
type Status = 'draft' | 'published' | 'removed'; type UserVisibleStatus = Exclude<Status, 'removed'>; const visible: UserVisibleStatus = 'draft'; // OK
Caractéristiques clés :
Peut-on utiliser Exclude pour des types ordinaires, et non des unions ?
Si T n'est pas un type union, mais fait partie de U — Exclude fonctionnera toujours, mais le résultat peut être never ou T, ce qui n'est pas toujours intuitif.
Exclude<'a', 'a'> // résultat : never Exclude<'a', 'b'> // résultat : 'a'
Exclude supprime-t-il toutes les mentions d'un type dans la structure d'un objet ?
Non, Exclude ne passe pas récursivement à travers les champs imbriqués du type, il exclut uniquement au niveau supérieur de l'union.
Comment fonctionne Exclude avec des interfaces et des types d'objets ?
Il compare l'entièreté du type, et non des propriétés individuelles. Ainsi, Exclude d'une union de plusieurs interfaces ne supprime que celles qui correspondent exactement à U.
interface A { x: number }; interface B { y: string }; // Exclude<A|B, B> donne : A (B correspond exactement)
Validation des rôles d'utilisateur via Exclude<UserRoles, 'admin'>, mais oublié que Exclude ne s'applique pas aux structures imbriquées — les droits 'admin:sub' n'ont pas été exclus.
Avantages :
Inconvénients :
Utilisation d'Exclude pour restreindre le API public aux actions : Exclude<Action, 'delete'>, ce qui exclut l'opération dangereuse.
Avantages :
Inconvénients :