I have an issue with union types and Exclude
(playground link):
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 }
Am I missing something related to union types and/or Exclude
?
I also tried with TS 4.4 and 4.2 with the same result.
Note:
We discovered the issue using type guards, you can see it in the playground here.
Exclude excludes types that are matching, not equal.
You are excluding Bar
from FooBar
. Bar
matches Bar
and Bar
matches Foo
. So you exclude both.
You could use something such as
type ExcludeExact<T, U> = T extends U ? U extends T ? T : never : never
Utility types like Pick
, Omit
work well with interface or types with properties since the second arg looks of keyof K
.
As yours is a union type, the TS compiler is unable to infer the correct behavior. You can try this
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>;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With