Skip to content

Infer variable type form return type #16218

Closed

Description

TypeScript Version: 2.3.2

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

        function findReconcilationCandidates(snapshot: any): Node[] {
            const res: Node[] = []
            // push some items on res   
            return res
        }

Expected behavior:

        function findReconcilationCandidates(snapshot: any): Node[] {
            const res = [] // type is inferred from return statement
            // push some items on res   
            return res
        }

Actual behavior:

Compile error:

'Variable 'res' implicitly has type 'any[]' in some locations where its type cannot be determined.'

Activity

  1. DanielRosenwasser commented on Jun 3, 2017

    @DanielRosenwasser
    Member

    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.

  2. mweststrate commented on Jun 3, 2017

    @mweststrate
    Author

    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 }.

  3. ahejlsberg commented on Jun 3, 2017

    @ahejlsberg
    Member

    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.

  4. mweststrate commented on Jun 3, 2017

    @mweststrate
    Author

    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?

  5. mweststrate commented on Jun 19, 2017

    @mweststrate
    Author

    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!

  6. locked and limited conversation to collaborators on Jun 14, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions