【问题标题】:Typescript convert type `typeof Foo` to `Foo`打字稿将类型`typeof Foo`转换为`Foo`
【发布时间】:2017-12-29 20:49:08
【问题描述】:

我正在开发一个通用 Typescript 接口,其中工厂类使用特定类进行实例化,并且具有负责创建该类的各种实例的方法。我似乎无法实现的理想类型接口如下:

class BaseModel { /* impl */ }
class Foo extends BaseModel { /* impl */ }
class Factory<T extends BaseModel> { /* impl */ }

let factory : Factory<Foo> = new Factory(Foo)
let fooInstance = factory.build() // returns type: `Foo`

但是我不知道如何在不影响返回类型或维护并行构造函数类型定义的情况下获得Factory&lt;T&gt; 的声明以实现此目的。

如果我只依赖我声明的类给出的类型,构建函数的返回类型总是BaseClass,另外我必须使用通用Factory&lt;typeof Foo&gt;而不是Factory&lt;Foo&gt;:

class BaseModel {
  static classMethod() : string {
    return 'i am class method'
  }

  hello() {
    return 'hello world'
  }
}
class Foo extends BaseModel {}

class Factory<T extends typeof BaseModel> {
  private _modelClass : T

  constructor(modelClass : T) {
    this._modelClass = modelClass
  }

  build() {
    return new this._modelClass()
  }

  echoClassMethod() {
    console.log(this._modelClass.classMethod())
  }
}

let factory : Factory<typeof Foo> = new Factory(Foo)
let fooInstance = factory.build() // Returns type `BaseClass` instead of `Foo`

但如果我希望工厂类型接口正常工作,我必须维护一个镜像typeof BaseModel 的并行类型定义,而是作为构造函数:

class BaseModel {
  static classMethod() : string {
    return 'i am class method'
  }

  hello() {
    return 'hello world'
  }
}
class Foo extends BaseModel {}

// Have to maintain a separate type that 
// mirrors the class interface of my target class
type BaseModelConstructor<T extends BaseModel> = {
  new(...args: any[]) : T 
  classMethod() : string
}

class Factory<T extends BaseModel> {
  private _modelClass : BaseModelConstructor<T>

  constructor(modelClass : BaseModelConstructor<T>) {
    this._modelClass = modelClass
  }

  build() {
    return new this._modelClass()
  }

  echoClassMethod() {
    console.log(this._modelClass.classMethod())
  }
}

let factory : Factory<Foo> = new Factory(Foo)
let fooInstance = factory.build() // Correctly returns type `Foo`

必须有更好的方法将typeof X 转换为X,反之亦然?

【问题讨论】:

    标签: typescript generics


    【解决方案1】:

    假设X 既是构造函数值的名称,也是构造函数值的名称 实例类型(当你声明 class X {...} 时会发生这种情况):


    更新:

    从 TypeScript 2.8 开始,有一个名为 InstanceType&lt;&gt;predefined type function 采用类构造函数的类型并计算其实例的类型,使用 conditional type inference 而不是查找。所以你现在可以使用InstanceType&lt;typeof X&gt;typeof XX。但是下面的(typeof X)['prototype'] 仍然有效。


    要从typeof XX,通常可以lookup typeof X 构造函数类型的prototype 属性。例如,在下面我将build() 的返回类型注释为T['prototype']

    class Factory<T extends typeof BaseModel> {
      private _modelClass : T
    
      constructor(modelClass : T) {
        this._modelClass = modelClass
      }
    
      // note the declared return type
      build(): T['prototype'] {
        return new this._modelClass()
      }
    
      echoClassMethod() {
        console.log(this._modelClass.classMethod())
      }
    }
    

    然后以下工作:

    let factory = new Factory(Foo)
    let fooInstance = factory.build() // Foo, as desired.
    

    这有帮助吗?祝你好运!

    【讨论】:

    • 这非常有用,可以完美解决我的问题。为简单起见,我最终添加了第二个具有默认值的泛型:class Factory&lt;T extends typeof BaseModel, M extends BaseModel=T['prototype'&gt; 以前不知道您可以以这种方式引用成员类型。应该有助于清理我的一些其他类型的代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-17
    • 2020-02-01
    • 2011-09-16
    • 2020-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多