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
In many cases I have a variable that holds a value to be eventually returned from the function. The type of this variable always matches the return type of the function. It would be awesome if the type of that variable can be inferred from the fact that it is returned, using return, from the function, if the function has an explicitly declared return type.
I am aware that inference is done the other way around, however, we always work with explicit return types on functions. We have linting rules enforcing this, as it is a good practice that helps code reviews and encourages api-first thinking.
Code
So currently I have to write
functionfindReconcilationCandidates(snapshot: any): Node[]{constres: Node[]=[]// push some items on res returnres}
Expected behavior:
functionfindReconcilationCandidates(snapshot: any): Node[]{constres=[]// type is inferred from return statement// push some items on res returnres}
Actual behavior:
Compile error:
'Variable 'res' implicitly has type 'any[]' in some locations where its type cannot be determined.'
In addition to Andy's point, this would be a pretty big change in our type system. We don't really do inference going "backwards" from latter statements. The type system works off of a declared type which is inferred from its declaration. That type is specialized by subsequent checks and assignments.
While there are the concepts of type argument inference and contextual types (which I mention because they have a sort of back-and-forth interaction), those are limited to the statement level.
Andy (Andrewkraft) (@Andy-MS) your examples are unclear to me; as both will result in compile errors (with strict null checks enabled). With out them, the infered type of f is any[], not number[]. See this playground examle
'Argument of type 'Cat' is not assignable to parameter of type 'never'.' 'Argument of type '1' is not assignable to parameter of type 'never'.'
EDIT: The examples (suprisinginly?) do not give compile errors if noImplicitAny is enabled
Daniel Rosenwasser (@DanielRosenwasser) I can imagine this is hard to solve generically, but I figured it would be pretty convenient, especially where a variable type could be inferred directly from the return statements, and normal type inference cannot deliver a "good" candidate.
Not being able to infer a good candidate is probably limited to empty arrays and empty object literals:
This annoyance is especially noticable with arrays; as [] is always inferred to never[], which is probably the only type in the system where I am pretty sure it is in 100% of the cases not the type I am looking for 😉
A similar case is where a lookup map (object) is returned, but initialized as const res = {}, and items are added later on the fly, and the return type is something like { [key:string]: Type }.
With --noImplicitAny enabled we use control flow analysis to determine the type of arrays with no type annotation. See #11432. This is why you're not seeing errors in your examples with --noImplicitAny. It sounds to me like this has the behavior you want without having to depend on return type annotations.
Anders Hejlsberg (@ahejlsberg), Daniel Rosenwasser (@DanielRosenwasser) thanks for the explanation. So, the noImplicitAny options results indeed in sane type inference in most cases (saddly don't have that flag enabled yet in the project I run into it). Never realized that this option actually influences type inferences, always thought it was just a flag that forces all things to be typed. So this option solves the original issue in many cases, so feel free to close this issue.
The inference without noImplicitAny of [] to never[] instead of any[] still puzzles me though. Is this for some good reason correct, or a bug indeed?
Closing the issue as the original question is answered. (The inferences of [] to never[] is imho a bug but not the original issue). Thanks for the answers!
Activity
DanielRosenwasser commentedon Jun 3, 2017
In addition to Andy's point, this would be a pretty big change in our type system. We don't really do inference going "backwards" from latter statements. The type system works off of a declared type which is inferred from its declaration. That type is specialized by subsequent checks and assignments.
While there are the concepts of type argument inference and contextual types (which I mention because they have a sort of back-and-forth interaction), those are limited to the statement level.
mweststrate commentedon Jun 3, 2017
Andy (Andrewkraft) (@Andy-MS) your examples are unclear to me; as both will result in compile errors (with strict null checks enabled). With out them, the infered type of
fisany[], notnumber[]. See this playground examle'Argument of type 'Cat' is not assignable to parameter of type 'never'.''Argument of type '1' is not assignable to parameter of type 'never'.'EDIT: The examples (suprisinginly?) do not give compile errors if
noImplicitAnyis enabledDaniel Rosenwasser (@DanielRosenwasser) I can imagine this is hard to solve generically, but I figured it would be pretty convenient, especially where a variable type could be inferred directly from the return statements, and normal type inference cannot deliver a "good" candidate.
Not being able to infer a good candidate is probably limited to empty arrays and empty object literals:
This annoyance is especially noticable with arrays; as
[]is always inferred tonever[], which is probably the only type in the system where I am pretty sure it is in 100% of the cases not the type I am looking for 😉A similar case is where a lookup map (object) is returned, but initialized as
const res = {}, and items are added later on the fly, and the return type is something like{ [key:string]: Type }.ahejlsberg commentedon Jun 3, 2017
With
--noImplicitAnyenabled we use control flow analysis to determine the type of arrays with no type annotation. See #11432. This is why you're not seeing errors in your examples with--noImplicitAny. It sounds to me like this has the behavior you want without having to depend on return type annotations.mweststrate commentedon Jun 3, 2017
Anders Hejlsberg (@ahejlsberg), Daniel Rosenwasser (@DanielRosenwasser) thanks for the explanation. So, the
noImplicitAnyoptions results indeed in sane type inference in most cases (saddly don't have that flag enabled yet in the project I run into it). Never realized that this option actually influences type inferences, always thought it was just a flag that forces all things to be typed. So this option solves the original issue in many cases, so feel free to close this issue.The inference without
noImplicitAnyof[]tonever[]instead ofany[]still puzzles me though. Is this for some good reason correct, or a bug indeed?mweststrate commentedon Jun 19, 2017
Closing the issue as the original question is answered. (The inferences of
[]tonever[]is imho a bug but not the original issue). Thanks for the answers!