5

I am writing a small model system for my current project. I would like the consumer of the library to be able to provide their own model definition to the API. The API should output instances of the user's model when querying the server.

// Library Code
interface InstanceConstructor<T extends BaseModel> {
    new(): T;
}

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

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

class BaseModel {
    refresh() {
        // Refresh returns a new instance, but it should be of 
        // type Model, not BaseModel.
    }
}

// User Code
class Model extends BaseModel {
    // Custom Model
    do() {
        return true;
    }
}

I can't figure out how to finish the pattern here. Just getting the factory to spit out the right instances is pretty easy, however things like clone/refresh on the BaseModel need to also return Model, and not any.

Updated 10/2

After trying typescript@next (technically 1.8-dev at this moment) I seem to be able to get around the issue where the model can reference itself (this) and the type system can follow it. However, I'm unable to

// Library Code
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, Custom Model
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();

I've opened an issue on the typescript tracker here: https://github.com/Microsoft/TypeScript/issues/5493

Updated 12/1 (Unsolved)

This, according to the typescript issue tracker, is not possible. The "Polymorphic this" feature only works for non-static class members which would exclude the constructor.

1 Answer 1

2

You'll need to use the special this type:

class BaseModel {
    refresh(): this {
        // Refresh returns a new instance, but it should be of 
        // type Model, not BaseModel.
    }
}

At time of writing, this feature is only available in nightly builds of TypeScript (npm install typescript@next), and will be available in TypeScript 1.7. See https://github.com/Microsoft/TypeScript/pull/4910 if you want to track the specific commit or read more about how this works

Sign up to request clarification or add additional context in comments.

1 Comment

Nice, now I know the name of what I need! I will try it with TS@next, thanks for the tip.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.