打字稿:在子方法中重写父类的静态工厂方法

时间:2018-08-08 11:31:39

标签: node.js typescript oop dependency-injection tdd

我在使用Typescript进行依赖项注入时遇到了一些问题。在每个类上,我添加了一个工厂静态方法,其中设置了所有依赖项。我这样做是出于测试目的,因此我仍然可以使用TDD方法。

现在,在子类中重写父类的工厂方法时遇到了一些问题。示例:

interface DepsA {
  a: string
}

interface DepsB extends DepsA {
  b: Child1
}

class Parent {
  constructor(protected deps: DepsA | DepsB) {}

  public static factory<T extends Parent>() {
    return new this({a: 'This is a nice Dependency'}) as T
  }
}

class Child1 extends Parent {}

class Child2 extends Parent {
  public static factory() {
    return new this({a: 'This is a nice Dependency', b: Child1.factory()})
  }
}

const child1 = Child1.factory<Child1>()
const child2 = Child2.factory()

我收到的错误是:

[ts]
Class static side 'typeof Child2' incorrectly extends base class static side 'typeof Parent'.
  Types of property 'factory' are incompatible.
    Type '() => Child2' is not assignable to type '<T extends Parent>() => T'.
      Type 'Child2' is not assignable to type 'T'.

我知道为什么会收到该错误,但是到目前为止,除了在Child2中重命名工厂静态方法外,不知道如何解决该错误。

更新:与该问题相关的错误报告,自动解释了为什么在工厂方法上使用泛型的原因:#26298

1 个答案:

答案 0 :(得分:1)

首先,有一个预定义的conditional type,名为 InstanceType ,它可以帮助您从静态成员中推断类的类型:

public static factory<T extends typeof Parent>(this: T) {
    return new this({ a: 'This is a nice Dependency' }) as InstanceType<T>
}

第二,如果您在子类中重写了静态方法或非静态方法,则该方法应具有兼容的签名,包括通用的内容。

因此,您的代码块可能如下所示(请参见Typescript Playground):

interface DepsA {
    a: string
}

interface DepsB extends DepsA {
    b: Child1
}

class Parent {
    constructor(public deps: DepsA | DepsB) {}

    public static factory<T extends typeof Parent>(this: T) {
        return new this({ a: 'This is a nice Dependency' }) as InstanceType<T>
    }
}

class Child1 extends Parent {}

class Child2 extends Parent {
    public static factory<T extends typeof Parent>(this: T) {
        return new this({a: 'This is a nice Dependency', b: Child1.factory()}) as InstanceType<T>
    }
}

const child1 = Child1.factory()  // Type: Child1
const child2 = Child2.factory()  // Type: Child2

从那里,使用deps在非静态成员中也可以返回正确的as this["deps"]类型而不是联合。但是您必须修改一下代码。

希望对您有所帮助;-)