Reputation: 1429
Why in the following code is Exclude<A,B>
resolving to the never
type? Can't the typescript compiler know (through static analysis) that A
and B
extend Parent
and thus Exclude<Choices, Parent>
should resolve to type C
?
interface Parent {}
interface A extends Parent {}
interface B extends Parent {}
interface C {}
type Choices = A | B | C
type Test = Exclude<Choices, Parent> // = type "never"???
const c: C = {}
const d: Test = c // Type 'C' is not assignable to type 'never'
I could hard code Parent = A | B
but I'm unsure why I need to.
Upvotes: 4
Views: 576
Reputation: 896
I created a type tool as follows
// It is the opposite operation to [exclude].
type Has<T, U> = U extends T ? U : never;
Usage is as follows
type A = {
a : number;
aa:number;
aaa:number;
}
type B = {
b : number;
}
type C = {
c : number;
}
type D = {
d : number;
}
// Here means the type A
type Node_HasA = Has<{
a : number;
}, A|B|C|D>
Upvotes: 0
Reputation: 5518
This is because TypeScript has duck typing. Specifically, since C
and Parent
are the same interface, C
is assignable to Parent
.
Specifically, this compiles:
const c: C = {};
const p: Parent = c;
So, although C
doesn't explicitly extend Parent
, TypeScript still says that C
is a Parent
.
If you want this to work, just add something to Parent
that C
doesn't have.
interface Parent { foo: string }
interface A extends Parent {}
interface B extends Parent {}
interface C {}
type Choices = A | B | C
type Test = Exclude<Choices, Parent> // = type C
const c: C = {}
const d: Test = c // works!
Upvotes: 2