Typescript 将类型 `typeof Foo` 转换为 `Foo`

问题描述 投票:0回答:1

我正在开发一个通用的 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<T>
的声明来实现此目的,而不影响返回类型或维护并行构造函数类型定义。

如果我只依赖于我声明的类给出的类型,则构建函数的返回类型始终为

BaseClass
,而且我必须使用泛型
Factory<typeof Foo>
而不是
Factory<Foo>
:

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个回答
12
投票

假设

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


更新:

从 TypeScript 2.8 开始,有一个名为 InstanceType<>

预定义类型函数
,它采用类构造函数的类型并使用条件类型推断而不是查找来计算其实例的类型。 因此,您现在可以使用
typeof X
X
InstanceType<typeof X>
。 但下面的
(typeof X)['prototype']
仍然有效。


要从

typeof X
X
,通常可以查找
prototype
构造函数类型的
typeof X
属性。 例如,在下面我将
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.

Playground 代码链接

© www.soinside.com 2019 - 2024. All rights reserved.