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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With