Typescript泛型:如何同时引用类定义和实例类型

时间:2019-06-04 20:47:25

标签: typescript generics

对不起,如果已经解决了,但是我的词汇使我失望:(

我正在尝试编写一个“集合”类,在实例化时,我给它一个“模型”类定义。集合实例需要能够删除“模型”的实例,但是还需要能够在该类上调用静态方法。

type Ctor<T> = new (...args: any[]) => T

class Model<T> {
  foo: string
  bar: string
  static myMethod() {}
}

class Extension extends Model<Extension> {
  foobar() {}
}

Extension.myMethod() // works
const e = new Extension()

e.foobar() // works

class Collection<T> {
  public model: T

  constructor(model: T) {
    this.model = model
  }

  getModelInstance() {
    // clearly this is problematic
    const Model = this.model as unknown as Ctor<T> 
    return new Model()
  }
}

现在当我尝试使用它时问题就变成了:

const c = new Collection(Extension)
c.model.myMethod() // works

const m = c.getModelInstance()
m.foobar() // works at runtime, TS compiler says 'Property 'foobar' does not exist on type 'typeof Extension'.'

所以我可以稍微重新定义我的构造函数/实例定义:

class Collection<T> {
  public model: Ctor<T>

  constructor(model: Ctor<T>) {
    this.model = model
  }

  getModelInstance() {
    const Model = this.model
    return new Model()
  }
}
const c = new Collection(Extension)
c.model.myMethod() // Property 'myMethod' does not exist on type 'Ctor<Extension>'.

const m = c.getModelInstance()
m.foobar() // works

但是这不起作用,因为Ctor丢弃了我的静态“上下文”。

这可能吗?似乎我丢失了类型信息的任何一种形式。

1 个答案:

答案 0 :(得分:1)

我相当确定这对您有用。相关的更改是对MyCollection类和InstanceType的使用。这里是in the playground

class Model<T> {
    foo: string;
    bar: string;
    static myStaticMethod() { }
}

class Extension extends Model<Extension> {
    myInstanceMethod() { }
}

Extension.myStaticMethod();
const e = new Extension();
e.myInstanceMethod();

class MyCollection<TConstructor extends new () => InstanceType<TConstructor>> {
    public modelConstructor: TConstructor

    constructor(modelConstructor: TConstructor) {
        this.modelConstructor = modelConstructor
    }

    getModelInstance() {
        return new this.modelConstructor();
    }
}

const collection = new MyCollection(Extension)
collection.modelConstructor.myStaticMethod();

const model = collection.getModelInstance();
model.myInstanceMethod();