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
typeT0=ReturnType<<T>(t: T)=>keyofT>;// anytypeExpectedReturnType=keyofunknown;// never
π Actual behavior
ReturnType fails and returns any
π Expected behavior
Given the fact that the upper bound of the type parameter T is unknown, I'd expect keyof unknown as result, i.e. never.
Additional information about the issue
This is somewhat related to #55667 and it comes from the attempts made to understand why #55714 failed to pass all the test cases.
We have:
typeReturnType<Textends(...args: any)=>any>=Textends(...args: any)=> infer R ? R : any
The problem seems to be located in compareSignaturesRelated, called by getConditionalType to resolve the ReturnType's inner conditional type. We have that source = <T>(t: T): keyof T is compared against target = (...args: any): never. This never is, in fact, the correct return type R that was successfully inferred.
Because source has a type parameter, instantiateSignatureInContextOf(source, target, ...) comes into play and we get a new source: (t: any): string | number | symbol. I'm not 100% sure about the logic of instantiateSignatureInContextOf, but it's worth noting that target is the second argument of the call above and the type of target's parameter is any. Therefore it seems that, from the source point of view, T becomes just any (and keyof any is exactly string | number | symbol).
We now have source = (t: any): string | number | symbol to be compared against target = (...args: any): never. This comparison fails because of the return types: string | number | symbol is not assignable to never, thus the assignability check also fails and we get the falseType as result, i.e. any.
Β
The example in this issue may seem intentionally crafted, and in fact it is, but the point was to highlight the same problem explained by this comment. There we have a similar issue with the source we get from instantiateSignatureInContextOf: any has been substituted with never inside ReturnType definition, therefore if source has a type parameter it will be instantiated with never and sometimes things don't end well.
This probably undermines the possibility of having an all-encompassing definition for ReturnTypeif we use a concrete type for the arguments. However you type the rest parameter inside it, I suppose you can always find a counterexample that uses a not-yet-instantiated type parameter to make the assignability check of the conditional fail.
The text was updated successfully, but these errors were encountered:
Just to say what's going on, given the fact the using a concrete type seems to a bad idea, the current attempt is to infer the arguments but discard them, and it seems promising.
π Search Terms
"ReturnType inference any"
π Version & Regression Information
This is the behavior in every version I tried
β― Playground Link
https://www.typescriptlang.org/play?#code/C4TwDgpgBAKgDFAvFAShYBXATgOxuCAHkJgD4AKYALlgEolSoBrCEAewDNZSBuAWABQAeiFQxAPQD8gwaEhQAogA9IAY2AQAJmky5885C3ZcMOJjjYB3HP2GiJkoA
π» Code
π Actual behavior
ReturnType
fails and returnsany
π Expected behavior
Given the fact that the upper bound of the type parameter
T
isunknown
, I'd expectkeyof unknown
as result, i.e.never
.Additional information about the issue
This is somewhat related to #55667 and it comes from the attempts made to understand why #55714 failed to pass all the test cases.
We have:
The problem seems to be located in
compareSignaturesRelated
, called bygetConditionalType
to resolve theReturnType
's inner conditional type. We have thatsource = <T>(t: T): keyof T
is compared againsttarget = (...args: any): never
. Thisnever
is, in fact, the correct return typeR
that was successfully inferred.Because
source
has a type parameter,instantiateSignatureInContextOf(source, target, ...)
comes into play and we get a newsource
:(t: any): string | number | symbol
. I'm not 100% sure about the logic ofinstantiateSignatureInContextOf
, but it's worth noting thattarget
is the second argument of the call above and the type oftarget
's parameter isany
. Therefore it seems that, from thesource
point of view,T
becomes justany
(andkeyof any
is exactlystring | number | symbol
).We now have
source = (t: any): string | number | symbol
to be compared againsttarget = (...args: any): never
. This comparison fails because of the return types:string | number | symbol
is not assignable tonever
, thus the assignability check also fails and we get thefalseType
as result, i.e.any
.Β
The example in this issue may seem intentionally crafted, and in fact it is, but the point was to highlight the same problem explained by this comment. There we have a similar issue with the
source
we get frominstantiateSignatureInContextOf
:any
has been substituted withnever
insideReturnType
definition, therefore ifsource
has a type parameter it will be instantiated withnever
and sometimes things don't end well.This probably undermines the possibility of having an all-encompassing definition for
ReturnType
if we use a concrete type for the arguments. However you type the rest parameter inside it, I suppose you can always find a counterexample that uses a not-yet-instantiated type parameter to make the assignability check of the conditional fail.The text was updated successfully, but these errors were encountered: