Closed
Description
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 T
type Callback<T> = (...args : any[]) => T;
declare function noReturnTypeInParam<
F extends Callback<3|5>
>(f: F): ReturnType<F>
//Expected: const noArg: 3
//Actual : const noArg: 3
const noArg = noReturnTypeInParam(
//Return type is 3
() => 3
);
//Expected: const withArg: 3
//Actual : const withArg: 3
const withArg = noReturnTypeInParam(
//Return type is 3
t => 3
);
//Innocent enough.
//Returns a T
type Callback<T> = (...args : any[]) => T;
//Forgive the contrived example
declare function withReturnTypeInParam<
F extends Callback<3|5>,
>(
f: F & (
ReturnType<F> extends 3 ?
unknown :
[
"Only 3 allowed, received",
ReturnType<F>
]
)
): ReturnType<F>
//Expected: const noArg: 3
//Actual : const noArg: 3
const noArg = withReturnTypeInParam(
//Return type is 3
() => 3
);
//Expected: const withArg: 3
//Actual : const withArg: 3|5
const withArg = 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): 3
t => 3
);
//Expected: const withArgAndExplicitReturnTypeAnnotation: 3
//Actual : const withArgAndExplicitReturnTypeAnnotation: 3|5
const withArgAndExplicitReturnTypeAnnotation = 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 => (3 as 3)
);
//Expected: const withExplicitlyTypedArg: 3
//Actual : const withExplicitlyTypedArg: 3
const withExplicitlyTypedArg = withReturnTypeInParam(
/*
Expected: No error
Actual : No error
*/
//Return type is `3`
//function(t: any): 3
(t : any) => 3
);
//Innocent enough.
//Returns a T
type Callback<T> = (...args : any[]) => T;
//Forgive the contrived example
declare function returnTypeAsTypeParam<
T extends 3|5,
>(
f: Callback<
& T
& (
T extends 3 ?
unknown :
[
"Only 3 allowed, received",
T
]
)
>
): T
//Expected: const noArg: 3
//Actual : const noArg: 3
const noArg = returnTypeAsTypeParam(
//Return type is 3
() => 3
);
//Expected: const withArg: 3
//Actual : const withArg: 3
const withArg = returnTypeAsTypeParam(
/*
Expected: No error
Actual : No error
*/
//Return type is `3`
//function(t: any): 3
t => 3
);
//Expected: const withArgAndExplicitReturnTypeAnnotation: 3
//Actual : const withArgAndExplicitReturnTypeAnnotation: 3
const withArgAndExplicitReturnTypeAnnotation = 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 => (3 as 3)
);
Related Issues:
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