TypeScript中的“extends”泛型约束

5

我正在使用TypeScript中的extends约束,如下所示:

class Animal {}
class Lion extends Animal {}
class Bear extends Animal {}

class ZooKeeper<T extends Animal> {
    constructor(p: T = new Animal()) {

    }
}

new ZooKeeper(new Animal());

但是p: T = new Animal()包含一个错误:

类型“Animal”不能赋值给类型“T”。

构造函数Animal(): Animal

为什么,我该怎么做,才能在Animal子类型的位置使用Animal

源代码

3个回答

3
将您的动物投向T键,它就会开始工作。
class ZooKeeper<T extends Animal> {
    constructor(p: T = <T>new Animal()) {

    }
}

根据您自己的评论(针对未来读者),您还可以执行以下操作:
class ZooKeeper<T extends Animal> {
    constructor(p: T = new Animal() as T) {

    }
}

应该提到的是,<T>/as T 不是强制类型转换,而是类型断言。它告诉编译器“即使它不是,也将动物视为类型 T”。例如,以下代码将失败:new ZooKeeper<Lion>().getAnimal().someLionMethod(),因为我们得到的动物实际上不是狮子,而是 Animal 类的一个实例。 - LukeSw
这个可以工作,但是非常错误。你为什么要使用通用的呢? - amik

2
您可以直接在构造函数参数声明中省略赋值,这对我来说似乎编译正常。如果需要,您甚至可以将该参数设置为可选项,以便留空。 更新:series0ne所指出的,该解决方案未提供默认的Animal实例(当没有提供时)。
class ZooKeeper<T extends Animal> {
    constructor(p?: T) {
    }
}

var zk = new ZooKeeper<Lion>(new Lion());
var zk2 = new ZooKeeper(new Animal());
var zk3 = new ZooKeeper();

ZooKeeper 类将被类型化,您可以访问 T 的特定子类属性。


这并没有解决问题 - 如果你查看生成的JS代码,你会发现p:T = new Animal()会发出一个默认实例(Animal的实例),如果没有提供一个实例。而你的实现不会这样做! - Matthew Layton
我看了JS的输出,你是对的,确实有区别。抱歉,我没有完全理解你的问题。 - ther
没问题,这都是学习过程中的一部分,我的朋友。如果您更新您的回答以纳入我的意见,我将撤销投票。 - Matthew Layton

1
实际上,你想要做的事情并不容易实现。因为AnimalT是不同的类型,所以不能将Animal赋值给T
考虑下面的例子:
class Lion extends Animal {
  roar() { … }
}
new ZooKeeper<Lion>().animal.roar();

您可以在这里运行它以查看它在运行时抛出异常,因为即使我们将Lion作为T类型传递,我们显式创建了Animal对象,该对象没有任何T类型成员。而且我们无法在构造函数中编写new T(),因为在运行时,关于类型的所有信息都不存在。

值得一提的是,只有在明确需要时才应使用构造函数<Type>objectobject as Type,因为它不是强制转换而是类型断言(它告诉编译器“将object视为Type,即使它不是”,因此当用作“强制转换”时可能会导致难以找到的错误。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接