假设我们有一个简单的继承案例:
class Animal {
// Return a shallow copy with all prototype functions
getClone(): Animal {
return Object.assign(Object.create(Object.getPrototypeOf(this)), this);
}
}
class Dog extends Animal {
woof() { console.log('Woof'); }
}
因此,乍一看,此代码可以正常工作。但是,当我尝试从Dog实例使用getClone()
时:
const dog = new Dog();
// Invalid since the superclass Animal doesn't contain the function woof()
dog.getClone().woof();
当然,我总是可以通过以面向对象的方式重写getClone()来解决此错误:
class Dog extends Animal {
woof() { console.log('Woof'); }
getClone(): Dog {
return super.getClone();
}
}
但是,可以说该项目扩大了规模,我需要创建100个动物类。在每个类中编写重写函数会很麻烦吗?另外,如果我需要在动物基类中添加一个函数,是否需要在每个子类中重载它?
因此,我想出了一个临时解决方案:使用泛型。
class Animal<T> {
getClone(): T {
return Object.assign(Object.create(Object.getPrototypeOf(this)), this);
}
}
class Dog extends Animal<Dog> {
woof() { console.log('Woof'); }
}
那么这段代码可以很好地工作,没有TSLint或编译错误。但是,如果在类创建后立即将泛型添加到超类中,真的安全吗?
它也有预期的缺陷。假设我们有一个名为changeNameThenGet(name: string)
的函数。如果未提供名称或名称无效,它将返回自身:
class Animal<T> {
name = 'Some Animal';
getClone(): T {
return Object.assign(Object.create(Object.getPrototypeOf(this)), this);
}
changeNameThenGet(name: string): T {
if (!name) {
// Typescript error. 'this' is an instance of Animal, not T
return this;
}
const newAnimal = this.getClone();
newAnimal.name = name;
return newAnimal;
}
}
似乎Typescript无法识别T是Animal的子类,我正在尝试寻找一种使其正常工作的方法。请注意,class Animal<T extends Animal<any>>
也不起作用。我可以说return this as any
可以解决这个问题,但归根结底,这只是一种解决方法。
那么你们认为解决此类问题的正确方法是什么?
答案 0 :(得分:1)
通常使用通用方法,因为在大多数语言中,没有办法告诉基类中的方法返回什么当前类型。幸运的是Typescript不是大多数语言。 Typescript允许在非静态方法中将this
用作类型,这正是您所需要的:
class Animal {
// Return a shallow copy with all prototype functions
getClone(): this {
return Object.assign(Object.create(Object.getPrototypeOf(this)), this);
}
}
class Dog extends Animal {
woof() { console.log('Woof'); }
}
new Dog().getClone().woof();
这是介绍此功能的Issue。