Skip to content

noImplicitAny incorrectly permits 'any' when returned via arrow function #7220

Description

@myitcv

Apologies for the vague title, I can't quite pin down the cause of this, hence the poor wording

$ tsc --version
1.9.0-dev.20160208

The problem is best described using the following example:

// using --noImplicitAny

let a = undefined;  // OK: error as expected: Variable 'a' implicitly has an 'any' type.

function mine<T>(meth: () => T): T {
    return meth();
}

// **Problem**: x has type 'any' below
// Should be a compiler error
let x = mine(() => {
    return undefined;
});

Activity

  1. added this to the milestone on Feb 24, 2016
  2. myitcv commented on Feb 24, 2016

    @myitcv
    Author

    Mohamed Hegazy (@mhegazy) - I see you've added the 'Community' milestone.

    CONTRIBUTING.md references this milestone but I have a further question.

    How are issues tagged with a milestone of 'Community' prioritised within the TypeScript core team?

    Or does the 'Community' milestone mean that this issue is essentially waiting for a contribution from non-core members?

    Thanks

  3. mhegazy commented on Feb 24, 2016

    @mhegazy
    Contributor

    Community means it is up for grabs, and the core team have not committed to fixing it within a specific milestone. that also applies to suggestions.
    You can look at all the "committed" bugs for a milestone to get a picture of what is planned.

  4. jods4 commented on Mar 24, 2016

    @jods4

    The problem is not x but () => undefined.

    x has the return type of mine, which is T, which is inferred from the lambda to be any.
    This is as legal as

    function f(): any {}
    
    let x = f(); // ok, any
    let x = mine<any>(() => undefined); // ok, any

    On the other hand the lambda () => undefined implicitly has return type any and this is generally caught by the compiler:

    let f = () => undefined;
    // error: Function expression, which lacks return-type annotation, implicitly has 'any' return type.

    But the lambda can't be immediately rejected, because its return type might be dictated by context. In fact the following is ok:

    // ok because of explicit type parameter dictating the return type
    let x = mine<any>(() => undefined);

    My guess is that the compiler is going full circle with the generic parameter.

    1. It can't reject () => undefined immediately when seeing it. It needs to check if the context implies a return type.
    2. When evaluating the context, T is inferred any from the lambda itself.
    3. Which then validates the lambda as having any return type.

    That might be tricky to sort out...

  5. DanielRosenwasser commented on Mar 24, 2016

    @DanielRosenwasser
    Member

    Linking in #7547 because it appears that we're also suffering here due to issues described in #241. I don't think you'd have run into this problem if we didn't widen the types so soon.

    Anders Hejlsberg (@ahejlsberg) Ryan Cavanaugh (@RyanCavanaugh) Jason Freeman (@JsonFreeman)

  6. JsonFreeman commented on Mar 26, 2016

    @JsonFreeman
    Contributor

    When should the error be reported? The lambda is inferentially typed by () => T, which does not imply a return type, correct? Then the lambda is widened - this is when I would expect the error to be reported. Do we hold back on reporting errors during inferential typing?

    Here's another thought. If the return expression were not widened, the error would still be missing because we do not report noImplicitAny errors resulting from widening after type argument inference. So while I agree that #241 should be fixed, I'm not sure that would cause the error be reported in this case.

  7. myitcv commented on Mar 29, 2016

    @myitcv
    Author

    Is this another instance of the same problem?

    interface Class<T> {
        new (...args: Array<any>): T;
    }
    
    class A<T> {
        private t: Class<T>;
    
        constructor(t: Class<T>) {
            this.t = t; 
        }
    }
    
    class B<T> {
        private f: T;
    }
    
    function Example<T>(a: Class<T>): B<T> {
        return new B<T>();
    }
    
    let x = Example(A); // type is B<A<any>>
  8. JsonFreeman commented on Mar 29, 2016

    @JsonFreeman
    Contributor

    Paul Jolly (@myitcv) I don't think that has to do with widening. I think the problem there is that in the process of inferring T for the example call, you end up having to match any in the parameter of the Class<T> constructor against Class<T> in the A constructor. I know the compiler does this for call signatures, though I'm not sure if the same mechanism is used for construct signatures.

  9. myitcv commented on Mar 29, 2016

    @myitcv
    Author

    Thanks Jason Freeman (@JsonFreeman) - does this warrant another issue tracking the 'problem' here?

  10. JsonFreeman commented on Mar 30, 2016

    @JsonFreeman
    Contributor

    Yes, I think that should be a new issue.

  11. DanielRosenwasser commented on Mar 30, 2016

    @DanielRosenwasser
    Member

    To clarify, I think we can use this issue to track that since a fix would potentially need to solve both. If it's doesn't, we can open a new one. Maybe Jason Freeman (@JsonFreeman) meant something else.

  12. JsonFreeman commented on Mar 30, 2016

    @JsonFreeman
    Contributor

    Sorry, didn't mean to manage the issue tracking. I just meant that I think the problems have two different (and independent) causes, so I imagine they'd need two different fixes. But that is a hunch.

  13. myitcv commented on Mar 30, 2016

    @myitcv
    Author
  14. danvk commented on Aug 27, 2021

    @danvk
    Contributor

    This seems to have been fixed, x in the example now has a type of undefined rather than any:

    image

    playground

  15. andrewbranch commented on Aug 27, 2021

    @andrewbranch
    Member

    It's an unreported any without --strictNullChecks (which defaults to enabled on the playground)

  16. Andarist commented on Aug 30, 2025

    @Andarist
    Contributor
  17. locked as resolved and limited conversation to collaborators on Mar 3, 2026
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

    BugA bug in TypeScriptHelp WantedYou can do this

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions