Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
myitcv opened this issue Feb 24, 2016 · 14 comments
Open
Labels
Bug A bug in TypeScript Help Wanted You can do this
Milestone

Comments

@myitcv
Copy link

myitcv commented Feb 24, 2016

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;
});
@mhegazy mhegazy added Bug A bug in TypeScript Help Wanted You can do this labels Feb 24, 2016
@mhegazy mhegazy added this to the Community milestone Feb 24, 2016
@myitcv
Copy link
Author

myitcv commented Feb 24, 2016

@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

@mhegazy
Copy link
Contributor

mhegazy commented Feb 24, 2016

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.

@jods4
Copy link

jods4 commented Mar 24, 2016

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

@DanielRosenwasser
Copy link
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.

@ahejlsberg @RyanCavanaugh @JsonFreeman

@JsonFreeman
Copy link
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.

@myitcv
Copy link
Author

myitcv commented Mar 29, 2016

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

@JsonFreeman
Copy link
Contributor

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

@myitcv
Copy link
Author

myitcv commented Mar 29, 2016

Thanks @JsonFreeman - does this warrant another issue tracking the 'problem' here?

@JsonFreeman
Copy link
Contributor

Yes, I think that should be a new issue.

@DanielRosenwasser
Copy link
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 @JsonFreeman meant something else.

@JsonFreeman
Copy link
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.

@myitcv
Copy link
Author

myitcv commented Mar 30, 2016

Thanks for clarifying @DanielRosenwasser

@danvk
Copy link
Contributor

danvk commented Aug 27, 2021

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

image

playground

@andrewbranch
Copy link
Member

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Help Wanted You can do this
Projects
None yet
Development

No branches or pull requests

8 participants