Exclude<T, U> es un tipo utilitario que apareció en TypeScript para restar un tipo de otro, cuando se requiere excluir algunos valores de un tipo union.
Originalmente, no había una forma conveniente en TypeScript de restar un tipo de otro. Al crear API genéricas, así como al realizar refactorizaciones, a menudo era necesario obtener un tipo "residual": todo, excepto los valores prohibidos. En lugar de realizar manipulaciones manuales con union, era necesario mantener varias interfaces similares.
Por ejemplo, cuando hay un tipo 'A | B | C', pero se necesita obtener un tipo sin B. Esto es a menudo requerido al construir parámetros de entrada complejos para funciones, filtrar valores permitidos y formar dinámicamente tipos.
Exclude resuelve este problema. Su firma simplificada es la siguiente:
type Exclude<T, U> = T extends U ? never : T;
Devuelve el tipo que excluye de T todos los miembros de U.
Ejemplo:
type Status = 'draft' | 'published' | 'removed'; type UserVisibleStatus = Exclude<Status, 'removed'>; const visible: UserVisibleStatus = 'draft'; // OK
Características clave:
¿Se puede usar Exclude para tipos normales, y no para unions?
Si T no es un tipo union, pero está dentro de U, Exclude funcionará igualmente, pero el resultado puede ser never o T, lo que no siempre es intuitivo.
Exclude<'a', 'a'> // resultado: never Exclude<'a', 'b'> // resultado: 'a'
¿Elimina Exclude todas las menciones de tipo en la estructura del objeto?
No, Exclude no pasa recursivamente por los campos anidados del tipo, solo excluye en el nivel superior del union.
¿Cómo funciona Exclude con interfaces y tipos objeto?
Compara todo el tipo, no propiedades individuales. Por lo tanto, Exclude de un union de varias interfaces elimina únicamente aquellas que coinciden completamente con U.
interface A { x: number }; interface B { y: string }; // Exclude<A|B, B> da: A (B coincide completamente)
Validación de roles de usuario a través de Exclude<UserRoles, 'admin'>, pero se olvidó que Exclude no se aplica a estructuras anidadas: los derechos 'admin:sub' no fueron excluidos.
Pros:
Contras:
Uso de Exclude para restringir el API público de acciones: Exclude<Action, 'delete'>, lo que excluye la operación peligrosa.
Pros:
Contras: