Reputation: 4028
There are a few questions already asked like this. But I think this a little more specific.
Please see this example:
interface Body {
legs: number;
}
interface Kingdom {
animalia: {
sound: string; // meow..
body: Body;
};
}
function GetBody<
Category extends keyof Kingdom,
B extends Kingdom[Category]["body"]
>(cat: Category): B {
// stuff..
return { legs: 4 }; // <==== Error!
}
// called like: GetBody('animalia').legs
The Error says:
Type '{ legs: number; }' is not assignable to type 'B'.
'{ legs: number; }' is assignable to the constraint of type 'B',
but 'B' could be instantiated with a different subtype of constraint 'Body'.ts(2322)
What am I doing it wrong here? How can I fix this?
Upvotes: 8
Views: 8509
Reputation: 1264
Your problem is that B extends Kingdom[Category]["body"]
does not mean that B
is Kingdom[Category]["body"]
, instead it means that B
must be assignable to Kingdom[Category]["body"]
.
So, as @Aluan pointed out, a type like {legs: number, eyes: 2}
is perfectly valid for B
. {legs: number, eyes: 2}
does extend Kingdom[Category]["body"]
.
This means that { legs: 4 }
, the object you return, couldn't be enough. It would be perfect if B
were exactly Kingdom[Category]["body"]
, but this is not always the case.
In your situation, there is no need for a generic. Indeed, it's wrong to use one because you need exactly Kingdom[Category]["body"]
:
function GetBody<
Category extends keyof Kingdom,
>(cat: Category): Kingdom[Category]["body"] {
return { legs: 4 };
}
Note: there is already a TS interface called Body
. Change the name of yours.
Upvotes: 7