TypeScript Version: 3.4.0-dev.20190207, 3.3.0
Search Terms:
type parameter, callback
Code
interface Bar<T> {
<B_RETURN>(
a: (aParam: B_RETURN) => any,
b: (bParam: T) => B_RETURN // B_RETURN is supposed to be inferred from here
): any
}
declare const bar: Bar<any>
bar((aParam) => 1, () => 'abc') // OK! `aParam` is `string`
bar((aParam) => 1, (bParam) => 'abc') // `aParam` is `{}`. Why?
bar((aParam) => 1, (bParam: any) => 'abc') // `aParam` is `string`. Again, why?
let arg2 = (bParam) => 'abc' ; bar((aParam ) => 1, arg2) // `aParam` is `string`. Again, why?
Expected behavior:
aParam should be string in each of the four examples
Actual behavior:
aParam is for some reason {} instead of string in the second example
Playground Link: link
I would be very grateful if someone can give me some quick directions (Is it a bug? What am I missing?). My work depends on it in a great degree.
P.S. Asked on stackoverflow and got no answer.
This is basically the dual of #29791 - inference on functions proceeds left-to-right, so during the inference of aParam in the first function we have not yet examined the body of the second function expression to determine its return type (which we believe will be context-sensitive, in other words depends on its parameter type).
@RyanCavanaugh Thank you, made it very clear for me. Except one part:
which we _believe_ will be context-sensitive, in other words depends on its parameter type
I am not sure how the return type can depend on parameter type if it's clear that the function returns string, because it returns string literal. Moreover, I am confused by the fact that unknown parameter (bParam) and parameter of type any (bParam: any) lead to different results. Maybe this is worth fixing? I feel that it's wrong. It's just a suggestion, because, I am satisified with the provided answer already and this issue can be closed.
Again, thank you very much, I hate mysteries and love when they become simple things, like you made them for me.
I am not sure how the return type can depend on parameter type if it's clear that the function returns
string, because it returns string literal.
We don't have a separate pass to say "Go dive into the function and check to see if all its return statements don't rely on its parameter type" - doing so would be expensive in light of the fact that extremely few real-world functions actually behave like that in practice.
Moreover, I am confused by the fact that unknown parameter (
bParam) and parameter of type any (bParam: any) lead to different results.
An unannotated parameter isn't the same as any -- it's one that we're going to try to infer a type for. Functions with type annotations aren't context-sensitive, thus get treated differently in the inference process.
@RyanCavanaugh Wow. That's another valuable insight of how the compiler works, thank you so much! If only there would be a way to know these algorithms of TS compiler without looking at it's source code and bothering you in issues.
I think I will close this issue as I don't have other questions and the "Design Limitation" badge probably means I should close it.
Thanks again!
Most helpful comment
We don't have a separate pass to say "Go dive into the function and check to see if all its return statements don't rely on its parameter type" - doing so would be expensive in light of the fact that extremely few real-world functions actually behave like that in practice.
An unannotated parameter isn't the same as
any-- it's one that we're going to try to infer a type for. Functions with type annotations aren't context-sensitive, thus get treated differently in the inference process.