Búsqueda de sitios web

Tipos de unión de Typescript no excluidos


Tengo un problema con los tipos de unión y Exclude (enlace al playground):

type Foo = {
  data: string;
  otherData: number;
};
type Bar = Omit<Foo,'otherData'>
// type Bar = { data: string; }; // Even this is not working
type FooBar = Foo | Bar;

type ShouldBeFoo = Exclude<FooBar, Bar>; // Not working
// ShouldBeFoo = never

type ShouldBeBar = Exclude<FooBar, Foo>; // Somehow working
// ShouldBeBar = { data: string }

¿Me estoy perdiendo algo relacionado con los tipos union y/o Exclude?

También intenté con TS 4.4 y 4.2 con el mismo resultado.


Nota:

Descubrimos el problema usando guardianes de tipo, puedes verlo en el playground aquí.

Respuesta #1

Exclude excluye tipos que son coincidentes, no iguales.

Estás excluyendo Bar de FooBar. Bar coincide con Bar y Bar coincide con Foo. Así que excluyes ambos.

Podrías usar algo como

type ExcludeExact<T, U> = T extends U ? U extends T ? T : never : never

Respuesta #2

Los tipos utilitarios como Pick, Omit funcionan bien con interfaces o tipos con propiedades ya que el segundo argumento tiene el aspecto de keyof K.

Como el tuyo es un tipo unión, el compilador de TS no puede inferir el comportamiento correcto. Puedes intentar esto

type Foo = {
    data: string;
    otherData: number;
};

type Bar = Omit<Foo, 'otherData'>

type FooBar = Foo | Bar;

type Reduce<T, K> = T extends K ? K : never;

type ShouldBeFoo = Reduce<FooBar, Foo>;
type ShouldBeBar = Reduce<FooBar, Bar>;


Artículos relacionados