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
typeDelegate<T>=()=>T;functionexecuteGeneric<X,DelegateTextendsDelegate<X>>(delegate: DelegateT): ReturnType<DelegateT>{//Type 'X' is not assignable to type 'ReturnType<DelegateT>'.constx: ReturnType<typeofdelegate>=delegate();//Type 'X' is not assignable to type 'ReturnType<DelegateT>'.consty: ReturnType<DelegateT>=delegate();//Type 'X' is not assignable to type 'ReturnType<DelegateT>'.returndelegate();}
Expected behavior:
Return successfully.
Intuitively, to me,
delegate is of typeDelegateT.
ReturnType<DelegateT> and ReturnType<typeof delegate> should be the same
However,
Actual behavior:
Type 'X' is not assignable to type 'ReturnType<DelegateT>'.
ReturnType<DelegateT> and ReturnType<typeof delegate> are the same, and both are not assignable from DelegateT, you can not assign a function that returns a string to a string.
I don't know why I didn't think of this shorter example.
functionexecuteGeneric<DelegateTextends()=>number>(delegate: DelegateT): ReturnType<DelegateT>{//Type 'number' is not assignable to type 'ReturnType<DelegateT>'.constx: ReturnType<typeofdelegate>=delegate();//Type 'number' is not assignable to type 'ReturnType<DelegateT>'.consty: ReturnType<DelegateT>=delegate();//Type 'number' is not assignable to type 'ReturnType<DelegateT>'.returndelegate();}
Direct function calls are evaluated according to their constraints. This is generally desirable:
functioninvokeAndMultiply<Textends()=>number>(a: T,b: T){// OK or no?returna()*b();}
In general you cannot multiply arbitrary types, so this example would be an error if we forced deferral of a()'s return type to ReturnType<T>.
It'd be a pretty substantial complexity trade-off to start deferring the return type evaluation, since anything you do with a generic type constrained to a function type would then need follow-on special handling.
Let's say we defer the evaluation of a()'s return type.
In this example, even if TS hasn't evaluated what ReturnType<T> is,
it should know that ReturnType<T> extends number.
And because of that, it should allow their multiplication, because you can multiply two number types and ReturnType<T> is a subtype of number; the result being just number.
My example is simple. So, deferring the evaluation of the type is also not an issue.
In general, if given this,
functionfoo<Fextends()=>T>(f : F) : ReturnType<F>{/* Current behaviour: `value` is of type `T`. Proposed behaviour: `value` is of type `(T & ReturnType<F>)`, where evaluation of `ReturnType<F>` is deferred. */constvalue=f();//Right now, we can do all things `T` can do because `value` is subtype of `T`./* This should now work because `(T & ReturnType<F>)` extends `ReturnType<F>`. */returnvalue;}
Actually, I don't know anything about the compiler internals but I'm quite pleased with the above suggestion =x
Is there anything about it that stands out as potentially dangerous?
Activity
mhegazy commentedon May 21, 2018
ReturnType<DelegateT>andReturnType<typeof delegate>are the same, and both are not assignable fromDelegateT, you can not assign a function that returns a string to a string.AnyhowStep commentedon May 21, 2018
Isn't
delegateof typeDelegateTanddelegate()of typeReturnType<DelegateT>?delegate()is not supposed to beX, it could beXbut it could also be something that extendsXBut it's saying that
delegate()is of typeXwhen it shouldn't be (intuitively, to me, anyway)mhegazy commentedon May 21, 2018
ah. sorry about that, did not see the call there.. yes. you are right about that.
AnyhowStep commentedon Nov 18, 2018
I don't know why I didn't think of this shorter example.
Playground
RyanCavanaugh commentedon Mar 13, 2019
This is a suggestion, not a bug.
Direct function calls are evaluated according to their constraints. This is generally desirable:
In general you cannot multiply arbitrary types, so this example would be an error if we forced deferral of
a()'s return type toReturnType<T>.It'd be a pretty substantial complexity trade-off to start deferring the return type evaluation, since anything you do with a generic type constrained to a function type would then need follow-on special handling.
AnyhowStep commentedon May 24, 2019
Let's say we defer the evaluation of
a()'s return type.In this example, even if TS hasn't evaluated what
ReturnType<T>is,it should know that
ReturnType<T>extendsnumber.And because of that, it should allow their multiplication, because you can multiply two
numbertypes andReturnType<T>is a subtype ofnumber; the result being justnumber.My example is simple. So, deferring the evaluation of the type is also not an issue.
In general, if given this,
Actually, I don't know anything about the compiler internals but I'm quite pleased with the above suggestion =x
Is there anything about it that stands out as potentially dangerous?
jtbandes commentedon Feb 16, 2022
What additional feedback would be useful on this request? I filed a duplicate in #47900.
My real-world use case boils down to this: