如何在继承下的Typescript中定义泛型构造函数? [英] How to define a generic constructor in typescript under inheritance?
问题描述
我正在使用打字稿,想要编写一个工厂函数来创建一个新的对象实例并提供要填充的属性数组.基本上是从现有对象到另一个(相关)类型的新实例的转换器.应该这样使用
I am using typescript and want to write a factory function to create a new object instance and provide an array of properties to be filled. Basically a converter from an existing object to a new instance of another (related) type. It should be used like this
const newA = A.from({ a: 1 });
const newC = C.from({ a: 1, b: 2, c: 9 });
我有这个工作(为清楚起见,省略了成员变量,而Object.create可能更简单,原因请参见下文)
I have this working (member variables omitted for clarity and Object.create could be simpler, see below for the reason)
class A {
static from(data: Partial<A>) : A {
const o = Object.create(A);
Object.assign(o, data);
return o;
}
}
只要我从此类继承,此方法就很好用.我不想像这样随时重新创建此功能
This works nicely as long as I inherit from this class. I do not want to recreate this function anytime like so
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;
}
}
以下代码段有效,但是当我两次调用该类时,我需要指定该类
The following snippet works, but I need to specify the class when I call it twice
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>({ ... });
并希望使用某种形式的泛型,即我想像这样的东西.
and want to use some form of generic, i.e. I imagine something like this.
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({ ... });
我想这在理论上是可能的,因为在编译时静态函数的上下文是已知的,并且您可以推断出类的类型,但是我没有弄清楚如何在签名定义中使用这种继承的类型.
I would guess that this is theoretically possible, since at compile time the context of the static function is known and you could infer the class type, but I did not figure out on how to use this inherited type in the signature definition.
这是一个好的(可接受的)模式吗?如果不行,我该怎么办?
Is this a good (acceptable) pattern and if not, what should I do?
感谢您的帮助!
推荐答案
您正在寻找对此功能的打开功能要求,microsoft/TypeScript#5863 ,但我没有知道它是否会实施.
You're looking for polymorphic this
types for static methods, but they are not currently supported in TypeScript. There's an open feature request for it, microsoft/TypeScript#5863 but I don't know if it will ever be implemented.
Luckily there are workarounds, one of which is mentioned here: use a generic method in which the this
parameter depends on the generic. For example:
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;
}
}
在这里,我们仅允许在作为 A
某些子类型的无参数构造函数的对象上调用 from()
,它们将返回该子类型.我将实现从 Object.create(this)
更改为 new this()
,只是为了表明我们关心无参数性"(毕竟,要求构造函数自变量调用 Object.create(this)
的子类很可能无法构造有效的实例.
Here we will only allow from()
to be called on objects which are no-arg constructors of some subtype of A
, and they will return this subtype. I changed the implementation from Object.create(this)
to new this()
just to show that we care about the "no-arg-ness" (after all, a subclass called with Object.create(this)
that required a constructor argument is likely to fail to construct a valid instance).
因此这有效,因为 B
是 B
实例的无参数构造函数:
So then this works, since B
is a no-arg constructor of B
instances:
class B extends A {
foo = "bar";
}
const b = B.from({}); // B
console.log(b.foo.toUpperCase()); // BAR
但是失败了,因为 Z
不是 Z
实例的无参数构造函数:
but this fails, since Z
is not a no-arg constructor of Z
instances:
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
好的,希望能有所帮助;祝你好运!
Okay, hope that helps; good luck!
这篇关于如何在继承下的Typescript中定义泛型构造函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!