I have an issue with generic types working with union types. In my case a function is defined using a union type and when I call this function with an element of one of the types in the union I get an error I have been trying to explain for the whole day.
I managed to summarize in the following lines of code :
interface IA {
a: string;
}
interface IB {
b: string;
}
type IAll = IA | IB;
interface IG<T> {
prop: T;
fct: (p: T) => void;
}
function fAll(p: IG<IAll>) {
return;
}
const a: IG<IA> = {
prop: {a: "aaa"},
fct: (p) => { return; }
};
fAll(a);
The last line fAll(a);
returns a typing error that I just can't explain:
Argument of type 'IG<IA>' is not assignable to parameter of type 'IG<IAll>'.
Types of property 'fct' are incompatible.
Type '(p: IA) => void' is not assignable to type '(p: IAll) => void'.
Types of parameters 'p' and 'p' are incompatible.
Type 'IAll' is not assignable to type 'IA'.
Type 'IB' is not assignable to type 'IA'.ts(2345)
Why can't an element of IA
be applied the type IAll
while IAll
is the union of IA
and IB
? From my understanding if IA
matches, checking for IB
is irrelevant.
Writing fAll(a as IG<IAll>);
fixes the issue but I don't understand why it should be necessary.
Thanks for your help !
The issue is that IG<IA> | IG<IB>
is not the same as IG<IA | IB>
. If you change your code to the first one it will work however you will not be able to call a function like that.
interface IA {
a: string;
}
interface IB {
b: string;
}
type IAll = IA | IB;
interface IG<T> {
prop: T;
fct: (p: T) => void;
}
function fAll(p: IG<IAll>) {
// p.fct will allow `IA | IB` as parameters. This is not what you're looking for.
p.fct({
b: "string"
})
return;
}
const a: IG<IA> = {
prop: {a: "aaa"},
fct: (p) => {
// This will log out `p.a`, but `p.a` doesn't have to be provided by `fAll` function (see above).
console.log(p.a);
}
};
fAll(a);
function fAllFixed(p: IG<IA> | IG<IB>) {
// Thats better!
p.fct({
b: "string"
})
return;
}
fAllFixed(a);
I had a similar question a while back, and got an amazingly detailed reply from jcalz (which I still don't fully understand...). I would encourage you to check that out: https://stackoverflow.com/a/58632009/5554464