You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
ReturnType<> of function intersection inconsistent. #31601
TypeScript Version: TS Playground version (3.4.1), 3.5.0-dev.20190523
Search Terms: ReturnType, function, intersection
Code
declareconstf: &(()=>{x: 4})&(()=>{y: 3});//OK//z is of type {x:4}constz=f();//OKconsthasX: {x: 4}=z;//Property 'y' is missing in type '{ x: 4; }' but required in type '{ y: 3; }'.consthasY: {y: 3}=z;/** * Expected: * OK * z is of type {x:4} * * Actual: * Property 'y' is missing in type '{ x: 4; }' but required in type '{ y: 3; }'. * z is of type {y:3} */constz2: ReturnType<typeoff>=f();/** * Expected: OK * Actual: Property 'x' is missing in type '{ y: 3; }' but required in type '{ x: 4; }'.*/consthasX2: {x: 4}=z2;/** * Expected: Property 'y' is missing in type '{ x: 4; }' but required in type '{ y: 3; }'. * Actual: OK*/consthasY2: {y: 3}=z2;
Expected behavior:
Since function intersections are implemented as overloads,
When inferring from a type with multiple call signatures (such as the type of an overloaded function), inferences are made from the last signature (which, presumably, is the most permissive catch-all case). It is not possible to perform overload resolution based on a list of argument types (this would require us to support typeof for arbitrary expressions, as suggested in #6606, or something similar).
If the intention is to get the "most permissive catch-all case", wouldn't using the union of return types of each individual overload be better?
I'm pretty sure I've written overloads where each overload returned different types, and the last one wasn't a "permissive catch-all". Especially for generic functions, where allowing such an overload would makes type checks useless, because the result would be something like unknown or unknown[].
I guess I'll just treat this as a gotcha' and be careful with how I structure overloads from now on
functionfoo(x : 1): number;functionfoo(x : 2): string;functionfoo(x : 1|2): number|string{thrownewError("Not implemented");}//This is `string`typer=ReturnType<typeoffoo>;typeReturnType_1<T>=(Textends(x: 1)=> infer R ?
R :
never);/* Kind of sad this is `never` and not `number`. If we really are talking overloads here, then shouldn't ReturnType_1<> try to find the overload that matches the type `(x : 1) => any`?*///nevertypert_1=ReturnType_1<typeoffoo>;typeReturnType_2<T>=(Textends(x: 2)=> infer R ?
R :
never);//stringtypert_2=ReturnType_2<typeoffoo>;
Activity
jack-williams commentedon May 26, 2019
I think this is working as intended. Conditional type inference is done from the last overload not the first:
#21496:
AnyhowStep commentedon May 26, 2019
Hmmm,
If the intention is to get the "most permissive catch-all case", wouldn't using the union of return types of each individual overload be better?
I'm pretty sure I've written overloads where each overload returned different types, and the last one wasn't a "permissive catch-all". Especially for generic functions, where allowing such an overload would makes type checks useless, because the result would be something like
unknownorunknown[].I guess I'll just treat this as a gotcha' and be careful with how I structure overloads from now on
fatcerberus commentedon May 26, 2019
I’m assuming by the “last overload”, it means the implementation signature, which is the most permissive case by definition.
AnyhowStep commentedon May 27, 2019
I just tested it,
Playground
typescript-bot commentedon May 30, 2019
This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.
AnyhowStep commentedon May 30, 2019
Wait, what about this?
#31601 (comment)
Surely it's worth considering =/
It would be nice if
ReturnType_1<>wasnumberand notnever.Is there a reason to not make
ReturnType_1<>returnnumber?AnyhowStep commentedon Nov 30, 2019
I randomly came across this,

It made me think of how TS implements function overloads using intersection types.
It made me chuckle.