有时候我们需要模板方法来构建关于类似事物抽象关系,例如:
abstract class Animal {
constructor(public head: string, public leg: string, public hand: string) {}
}
class Bird extends Animal {}
class Human extends Animal {}
class Cat extends Animal {}
// more...
相应地,我们还需要一些函数来创建上面的Class的示例:
function createBird(head: string, leg: string, hand: string) {
return new Bird(head, leg, hand)
}
function createHuman(head: string, leg: string, hand: string) {
return new Human(head, leg, hand)
}
function createCat(head: string, leg: string, hand: string) {
return new Cat(head, leg, hand)
}
但我认为这不够优雅,因为里面有很多重复的内容。更糟糕的是,如果我们想改变抽象类'Animal':
abstract class Animal {
constructor(public head: string, public leg: string, public hand: string, public foot:string) {}
}
我在构造函数中添加了一个参数,接下来,我必须修改每个创建子类示例的函数,这太糟糕了。我的解决方案如下:
function createClass<T extends typeof Animal>(C: T, head: string, leg: string, hand: string) {
return new C(head, leg, hand)
}
const bird = createClass(Bird, '', '', '')
const human = createClass(Human, '', '', '')
const cat = createClass(Cat, '', '', '')
但是它会提示类型错误,即抽象类不能被示例化。我不知道如何导出正确的类型,因此请求帮助
1条答案
按热度按时间2skhul331#
最通用的
createClass
版本根本不关心Animal
或特定的构造函数参数类型列表。相反,它将接受任何具体的构造函数对象和该构造函数所期望的参数列表,并返回创建的示例:该函数是
A
中的generic,参数列表和T
,示例类型。C
参数有一个构造签名new (...a: A) => T
,这意味着如果你用A
类型的参数列表new
它,你会得到一个T
。这将适用于您的示例:
以及你想使用的任何其他构造函数:
因此,它将自动适应
Animal
构造函数参数类型的任何更改,或者如果Animal
的任何子类具有不同的构造函数参数类型列表。如果你真的想限制
C
输入到Animal
构造函数,以防止createClass(Date, 1686749440441);
,你可以通过约束T
来做到这一点:Playground链接到代码