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

Over-eager inference with ThisType & homomorphic mapped types #18805

Closed
DanielRosenwasser opened this issue Sep 27, 2017 · 2 comments
Closed
Labels
Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. Suggestion An idea for TypeScript

Comments

@DanielRosenwasser
Copy link
Member

@ahejlsberg and I have spoken about this a few times offline, but @bterlson was asking if we had an issue tracking this problem.

We've been working with Vue's API to try to give users a better experience. Unfortunately, this is still a very easy gotcha to fall into.

As a boiled down case, try running the following example with noImplicitAny and noImplicitThis:

type ComputedOf<T> = {
    [K in keyof T]: () => T[K]
}

declare function foo<P, C>(options: {
    props: P,
    computed: ComputedOf<C>
} & ThisType<P & C>): void;

foo({
    props: { x: 10, y: 20 },
    computed: {
        bar() {
            return this.x;
        }
    }
});

Here, you'll get a problem on bar and on the x in this.x, you'll get:

'bar' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.

Property 'x' does not exist on type '{ bar(): any; }'.

The problem surfaces as soon as any value on this is used in producing the return value of a computed method.

I forget exactly why this occurs, but it has to do with circularities in trying to draw inferences to C which is wrapped in a homomorphic mapped type. @ahejlsberg can fill me in here.

The solution for users is to add a return type annotation to bar which is not obvious, but it prevents type argument inference from type-checking the internals of the method, and avoids the circularity problem. Ideally, users should not have to think about this.

@DanielRosenwasser DanielRosenwasser added Bug A bug in TypeScript Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. labels Sep 27, 2017
@yortus
Copy link
Contributor

yortus commented Dec 18, 2017

I just spent a few hours figuring out why inference was failing sometimes for one of my generic functions, finally narrowing it down to whether or not this.someProp was referenced in a return expression of a method inside an object. I suspected something strange going on with ThisType and that lead me to this issue. Thanks @DanielRosenwasser for the workaround (adding a return annotation to the method).

I agree that it is not at all obvious. It's very surprising to see infered types totally change depending what a method returns, with no obvious causal link for the changed inference.

@RyanCavanaugh
Copy link
Member

This works now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

4 participants