0

我正在使用打字稿并想编写一个工厂函数来创建一个新的对象实例并提供一个要填充的属性数组。基本上是从现有对象到另一种(相关)类型的新实例的转换器。应该这样使用

const newA = A.from({ a: 1 });
const newC = C.from({ a: 1, b: 2, c: 9 });

我有这个工作(为清楚起见省略了成员变量,Object.create 可能更简单,原因见下文)

class A {
  static from(data: Partial<A>) : A {
    const o = Object.create(A);
    Object.assign(o, data);
    return o;
  }
}

只要我从这个类继承,它就可以很好地工作。我不想像这样随时重新创建此功能

class A {
  static from(data: Partial<A>) : A {
    const o = Object.create(A);
    Object.assign(o, data);
    return o;
  }
}

class B extends A {
static from(data: Partial<B>) : B {
    const o = Object.create(B);
    Object.assign(o, data);
    return o;
  }
}

以下代码段有效,但我需要在调用两次时指定类

class A {
  ...
  static from<T extends A>(data: Partial<T>) : T {
    const o = Object.create(this);
    Object.assign(o, data);
    return o;
  }
}

const newC = C.from<C>({ ... });

并想使用某种形式的通用,即我想象这样的事情。

class A {
  static from<T extends this>(data: Partial<T>) : A {
    const o = Object.create(this);
    Object.assign(o, data);
    return o;
  }
}

const new C = C.from({ ... });

我猜这在理论上是可能的,因为在编译时静态函数的上下文是已知的,您可以推断类类型,但我没有弄清楚如何在签名定义中使用这个继承的类型。

这是一个好的(可接受的)模式吗?如果不是,我该怎么办?

任何帮助表示赞赏!

4

1 回答 1

2

您正在寻找静态方法的多态this类型,但 TypeScript 目前不支持它们。有一个开放的功能请求,microsoft/TypeScript#5863,但我不知道它是否会被实现。

幸运的是,有一些变通方法,这里提到了其中之一:使用参数依赖于泛型的泛型方法。例如:this

class A {
    static from<T extends A>(this: new () => T, data: Partial<T>): T {
        const o = new this(); // no-arg constructor
        Object.assign(o, data);
        return o;
    }
}

在这里,我们将只允许from()在某些子类型的无参数构造函数的对象上调用A,并且它们将返回此子类型。我将实现从更改Object.create(this)new this()仅表明我们关心“无参数”(毕竟,使用Object.create(this)需要构造函数参数调用的子类可能无法构造有效实例)。

那么这是可行的,因为B它是B实例的无参数构造函数:

class B extends A {
    foo = "bar";
}
const b = B.from({}); // B
console.log(b.foo.toUpperCase()); // BAR

但这失败了,因为Z它不是Z实例的无参数构造函数:

class Z extends A {
    constructor(public bar: string) {
        super();
    }
}
const z = Z.from({}); // error!
// -----> ~
// typeof Z is not assignable to new () => Z
console.log(z.bar.toUpperCase());  // error at runtime, z.bar is undefined

好的,希望有帮助;祝你好运!

Playground 代码链接

于 2020-01-16T19:33:08.623 回答