"Getter and setter types do not agree" on identical inlined type definitions

Topics: General, Language Specification
Mar 15, 2013 at 3:36 PM
These three classes illustrate a compiler issue that I consider a flaw:
interface BaseInterface { /* ... */ };
interface Implementor { new (): BaseInterface; };

class notInlined {
    private newableType: Implementor;
    private instance: BaseInterface;

    public set NewableType(value: Implementor) {
        this.newableType = value;

        if (value) this.instance = new value();
    }

    public get NewableType(): Implementor {
        return this.newableType;
    }
}

class inlined {
    private newableType: { new (): BaseInterface; };
    private instance: BaseInterface;

    public set NewableType(value: { new (): BaseInterface; }) {
        this.newableType = value;

        if (value) this.instance = new value();
    }

    public get NewableType(): { new (): BaseInterface; } { // *** "Getter and setter types do not agree"
        return this.newableType;
    }
}

class inlined2 {
    private newableType: { new (): BaseInterface; };
    private instance: BaseInterface;

    public set NewableType(value: { new (): BaseInterface; }) {
        this.newableType = value;

        if (value) this.instance = new value();
    }

    public get NewableType() { // *** "Getter and setter types do not agree"
        return this.newableType;
    }
}
The notInlined example compiles fine but the inlined and inlined2 example gets an error "Getter and setter types do not agree". inlined2 is only different in that its getter omits its return type specification.

I sorta understand that the reason for this error could be that while the type definitions are identical, each is compiled as a distinct type and so the type inferencer sees them as different.

But the rest of the language is so ducky, I think this ought to be accommodated too. See inlined3, below! NewableType____() getter has a different name but does specify the type. This example has no errors EVEN THOUGH the return type of the getter is distinctly defined from that of private newableType.
class inlined3 {
    private newableType: { new (): BaseInterface; };
    private instance: BaseInterface;

    public set NewableType(value: { new (): BaseInterface; }) {
        this.newableType = value;

        if (value) this.instance = new value();
    }

    public get NewableType____(): { new (): BaseInterface; } {
        return this.newableType;
    }
}
Coordinator
Mar 18, 2013 at 3:09 PM
The inline and inlined2 examples look like there's a bug in the getter/setter type resolution. I'll file this one so we can take a look at it.

Not sure about inlined3, as I don't see how the types differ between newableType and NewableType___'s return. Aren't they both { new (): BaseInterface; }?
Coordinator
Mar 18, 2013 at 3:09 PM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.
Mar 18, 2013 at 3:36 PM
Hi Jon,

Thanks!

I'm not sure what you mean about inlined3. I think you think I was saying that inlined3 doesn't work. Perhaps based on my ambiguous usage of "distinctly"?

My point is that inlined3 DOES work. In 1 and 2, the getter/setter names are the same so they have to match but the (assumed) bug says they don't match. I was asking why does 3 work fine, if there is a good reason for 1 and 2 not to work.

Inlined3 is a counter-example showing that the type resolver can otherwise recognize that the types are identical. And I included this because it illustrates both the narrowing and widening type cases. If I only tested the setter, well maybe the narrowing case works but not the widening case or vise versa.

You get me?
Coordinator
Mar 18, 2013 at 4:48 PM
This is just a bug (see http://typescript.codeplex.com/workitem/691) -- if the setter appears before the getter and the type is any anonymous type, you'll get this error. As a work-around, just move the getter above the setter.