Skip to content

ReturnType<F> in parameter of generic function breaks inference when F has one implicitly typed param #33042

Description

@AnyhowStep

TypeScript Version: 3.5.1

Search Terms:

  • ReturnType
  • Implicit type annotation
  • Generic function
  • Parameter

Code

This is me opening a new issue for #29133

I have three separate code snippets, please bear with me =(

//Innocent enough.//Returns a TtypeCallback<T>=(...args : any[])=>T;declarefunctionnoReturnTypeInParam<FextendsCallback<3|5>>(f: F): ReturnType<F>//Expected: const noArg: 3//Actual : const noArg: 3constnoArg=noReturnTypeInParam(//Return type is 3 ()=>3);//Expected: const withArg: 3//Actual : const withArg: 3constwithArg=noReturnTypeInParam(//Return type is 3 t=>3);

Playground

//Innocent enough.//Returns a TtypeCallback<T>=(...args : any[])=>T;//Forgive the contrived exampledeclarefunctionwithReturnTypeInParam<FextendsCallback<3|5>,>(f: F&(ReturnType<F>extends3 ?
unknown :
["Only 3 allowed, received",ReturnType<F>])): ReturnType<F>//Expected: const noArg: 3//Actual : const noArg: 3constnoArg=withReturnTypeInParam(//Return type is 3 ()=>3);//Expected: const withArg: 3//Actual : const withArg: 3|5constwithArg=withReturnTypeInParam(/* Expected: No error Actual : Argument of type '(t: any) => 3' is not assignable to parameter of type 'Callback<3 | 5> & ["Only 3 allowed, received", 3 | 5]'. *///Return type is `3`//function(t: any): 3t=>3);//Expected: const withArgAndExplicitReturnTypeAnnotation: 3//Actual : const withArgAndExplicitReturnTypeAnnotation: 3|5constwithArgAndExplicitReturnTypeAnnotation=withReturnTypeInParam(/* Expected: No error Actual : Argument of type '(t: any) => 3' is not assignable to parameter of type 'Callback<3 | 5> & ["Only 3 allowed, received", 3 | 5]'. *///We *force* the return type to be 3//Return type is `3`//function(t: any): 3(t) : 3=>(3as3));//Expected: const withExplicitlyTypedArg: 3//Actual : const withExplicitlyTypedArg: 3constwithExplicitlyTypedArg=withReturnTypeInParam(/* Expected: No error Actual : No error *///Return type is `3`//function(t: any): 3(t : any)=>3);

Playground

//Innocent enough.//Returns a TtypeCallback<T>=(...args : any[])=>T;//Forgive the contrived exampledeclarefunctionreturnTypeAsTypeParam<Textends3|5,>(f: Callback<&T&(Textends3 ?
unknown :
["Only 3 allowed, received",T])>): T//Expected: const noArg: 3//Actual : const noArg: 3constnoArg=returnTypeAsTypeParam(//Return type is 3 ()=>3);//Expected: const withArg: 3//Actual : const withArg: 3constwithArg=returnTypeAsTypeParam(/* Expected: No error Actual : No error *///Return type is `3`//function(t: any): 3t=>3);//Expected: const withArgAndExplicitReturnTypeAnnotation: 3//Actual : const withArgAndExplicitReturnTypeAnnotation: 3constwithArgAndExplicitReturnTypeAnnotation=returnTypeAsTypeParam(/* Expected: No error Actual : No error *///We *force* the return type to be 3//Return type is `3`//function(t: any): 3(t) : 3=>(3as3));

Playground

Related Issues:

#29133

#32540 (comment)


I hope this is concise enough ><
I've commented all the relevant locations with what is expected and what actually happens.

Snippets 2 (withReturnTypeInParam) and 3 (returnTypeAsTypeParam) are expected to have the same behaviour because they mean the same thing semantically (to me).

They are just expressed differently syntactically.

I just have trouble understanding why snippet 2 breaks unless I have an explicit type annotation. I'm 99% sure it has to be a bug.

And I have trouble understanding why snippet 3 is OK

Metadata

Metadata

Labels

Working as IntendedThe behavior described is the intended behavior; this is not a bug

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions