Skip to content

Polymorphic "this" isn't polymorphic in some cases #5493

Closed
@xealot

Description

@xealot

Sorry for the crap title, I'm not entirely sure what is going on but I think it's a bug. I also think this is somewhat related to #5449 but am unsure.

Library Example:

export interface InstanceConstructor<T extends BaseModel> {
    new(fac: Factory<T>): T;
}

export class Factory<T extends BaseModel> {
    constructor(private cls: InstanceConstructor<T>) {}

    get() {
        return new this.cls(this);
    }
}

export class BaseModel {
    constructor(private fac: Factory<this>) {}

    refresh() {
        // get returns a new instance, but it should be of
        // type Model, not BaseModel.
        return this.fac.get();
    }
}

User Code Example:

export class Model extends BaseModel {
    do() {
        return true;
    }
}

// Kinda sucks that Factory cannot infer the "Model" type
let f = new Factory<Model>(Model);
let a = f.get();

let b = a.refresh();

The issue that the compiler complains about is as follows:

error TS2345: Argument of type 'typeof Model' is not assignable to parameter of type 'InstanceConstructor<Model>'.
  Types of parameters 'api' and 'api' are incompatible.
    Type 'Factory<this>' is not assignable to type 'Factory<Model>'.
      Type 'this' is not assignable to type 'Model'.
        Type 'BaseModel' is not assignable to type 'Model'.
          Property 'do' is missing in type 'BaseModel'.

If I change the extended model to be specific it errors in different way, but same theme.

export class Model extends BaseModel {
    constructor(fac: Factory<Model>) {
        super(fac);
    }

    do() {
        return true;
    }
}
error TS2345: Argument of type 'Factory<Model>' is not assignable to parameter of type 'Factory<this>'.
  Type 'Model' is not assignable to type 'this'.

I think the reason is because this isn't being polymorphic in either the template or the constructor. When this is analyzed in the constructor of BaseModel it seems to stick with that context.

I initially posted about the use of polymorphic this which was answered by @RyanCavanaugh http://stackoverflow.com/questions/33443793/create-a-generic-factory-in-typescript

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions