如果变量是超类类型,打字稿不允许子类方法
Typescript do not allow subclasses methods if variable is superclass type
我得到了一些 typescript 接口,抽象 class 并实现了 sub-classes:
// Animal classes
abstract class Animal {
abstract sound(): string;
constructor(public name: string) {
}
eat(food: string): string {
return "I eat this now: " + food;
}
}
class Snake extends Animal{
constructor() {
super("Snake");
}
sound() {
return "Sssssss";
}
}
class Owl extends Animal{
constructor() {
super("Owl");
}
sound() {
return "Hu-huu";
}
// Owl can also fly!
fly() {
return "I can flyyyy";
}
}
// Box classes
interface BoxInterface {
animal: Animal;
}
class Box implements BoxInterface {
animal: Animal;
constructor(animal: Animal) {
this.animal = animal;
}
}
如您所见,我们在方框中有一个 Box
和某种 Animal
- 在我们的示例中,它可以是 Snake
或 Owl
.
现在我们可以在里面创建 Box
和 Owl
。
let box = new Box( new Owl() );
现在的问题 - 使用在 superclass 中声明的任何方法都完全没问题:
box.animal.sound(); // this is fine
但是正如你所看到的 Owl 有额外的功能 fly()
并且因为 fly 没有在 Animal
中声明它抛出:
box.animal.fly(); // Property 'fly' does not exist on type 'Animal'.
创建普通变量时也会发生同样的情况:
let animal:Animal;
animal = new Owl();
animal.fly();
因为加法 Animal class 不必是抽象的,它可以是普通的 class 或接口 - 结果是一样的。
我的问题是:如果我的 class 是其他 class 的超集,为什么打字稿会抛出它。我认为接口和类型的主要思想是保证对象具有一些属性,例如本例中的 eat()
或 sound()
。
我是 typescript 的新手,所以可能是我遗漏了一些东西,无论如何我如何才能实现某些变量必须是某种类型但允许在 subclasses 中使用其他方法?
因为Box
es只能保证里面有Animal
s。并非所有 Animal
都可以 fly()
。
您可以将 (type assert) Box
的 Animal
投射到 Owl
,然后 然后 让它飞起来:
(box.animal as Owl).fly()
因为 typescript 不会为 animal: Animal;
执行推理类型
由于您将动物定义为 Animal
,因此只有 Animal
中定义的方法和字段可用。
这是强类型工作的方式。
如果您将动物声明为:
animal
或
animal : any
您将能够对其调用任何方法,但您将失去类型检查。
作为解决方法,如果动物是 Owl
。
,您可以使用强制转换来操纵 Owl
Type assertions are a way to tell the compiler “trust me, I know what
I’m doing.” A type assertion is like a type cast in other languages,
but performs no special checking or restructuring of data. It has no
runtime impact, and is used purely by the compiler. TypeScript assumes
that you, the programmer, have performed any special checks that you
need.
if (box.animal instanceof Owl){
(box.animal as Owl).fly
}
但更好的方法是使用通用的 Box
:
class Box<T extends Animal> implements BoxInterface {
animal: T
constructor(animal: T) {
this.animal = animal
}
}
现在你可以写:
let box = new Box<Owl>(new Owl());
box.animal.sound()
box.animal.fly()
无论如何,正如 IMSoP 所说:如果您想应用特定于 [=18= 的方法,您必须在某些时候知道您拥有的是 Owl
].
你是对的,基础 class 合同保证了 最少 一组已知可用于其所有子类型的方法。
但是,TypeScript 在这里强制实施了一个额外的约束,即您应该只调用您知道 在您拥有的对象上可用的方法。
在这种情况下,您在编写代码时所知道的 box.animal.fly();
就是您有一个 Animal
;因此,你应该只调用 all 动物拥有的方法。
想想如果没有这张支票会发生什么:
let animal:Animal;
animal = new Snake();
animal.fly();
您会在运行时遇到某种错误。类型检查器的想法就是为你发现这种可能性,并让你写出"safe"这个意义上的代码。
这是一个面向对象的问题。当您声明某种类型的变量并为其赋值时,该值(某种)有两种类型:运行时类型和静态(编译时)类型。编译器考虑的类型是为该变量声明的类型(它是动物,而不是 Owl,因此不能有方法 fly()
)。这对覆盖方法有影响(它们可以通过静态或动态信息解决,具体取决于语言规范)。有关详细信息,请查看
What is the difference between statically typed and dynamically typed languages?
https://en.wikipedia.org/wiki/Multiple_dispatch
所有其他答案均有效。
对于你的问题,你最好使用泛型
class Box<T extends Animal> {
constructor(public animal: T) { }
}
const box = new Box(new Owl())
box.animal.fly()
我得到了一些 typescript 接口,抽象 class 并实现了 sub-classes:
// Animal classes
abstract class Animal {
abstract sound(): string;
constructor(public name: string) {
}
eat(food: string): string {
return "I eat this now: " + food;
}
}
class Snake extends Animal{
constructor() {
super("Snake");
}
sound() {
return "Sssssss";
}
}
class Owl extends Animal{
constructor() {
super("Owl");
}
sound() {
return "Hu-huu";
}
// Owl can also fly!
fly() {
return "I can flyyyy";
}
}
// Box classes
interface BoxInterface {
animal: Animal;
}
class Box implements BoxInterface {
animal: Animal;
constructor(animal: Animal) {
this.animal = animal;
}
}
如您所见,我们在方框中有一个 Box
和某种 Animal
- 在我们的示例中,它可以是 Snake
或 Owl
.
现在我们可以在里面创建 Box
和 Owl
。
let box = new Box( new Owl() );
现在的问题 - 使用在 superclass 中声明的任何方法都完全没问题:
box.animal.sound(); // this is fine
但是正如你所看到的 Owl 有额外的功能 fly()
并且因为 fly 没有在 Animal
中声明它抛出:
box.animal.fly(); // Property 'fly' does not exist on type 'Animal'.
创建普通变量时也会发生同样的情况:
let animal:Animal;
animal = new Owl();
animal.fly();
因为加法 Animal class 不必是抽象的,它可以是普通的 class 或接口 - 结果是一样的。
我的问题是:如果我的 class 是其他 class 的超集,为什么打字稿会抛出它。我认为接口和类型的主要思想是保证对象具有一些属性,例如本例中的 eat()
或 sound()
。
我是 typescript 的新手,所以可能是我遗漏了一些东西,无论如何我如何才能实现某些变量必须是某种类型但允许在 subclasses 中使用其他方法?
因为Box
es只能保证里面有Animal
s。并非所有 Animal
都可以 fly()
。
您可以将 (type assert) Box
的 Animal
投射到 Owl
,然后 然后 让它飞起来:
(box.animal as Owl).fly()
因为 typescript 不会为 animal: Animal;
由于您将动物定义为 Animal
,因此只有 Animal
中定义的方法和字段可用。
这是强类型工作的方式。
如果您将动物声明为:
animal
或
animal : any
您将能够对其调用任何方法,但您将失去类型检查。
作为解决方法,如果动物是 Owl
。
Owl
Type assertions are a way to tell the compiler “trust me, I know what I’m doing.” A type assertion is like a type cast in other languages, but performs no special checking or restructuring of data. It has no runtime impact, and is used purely by the compiler. TypeScript assumes that you, the programmer, have performed any special checks that you need.
if (box.animal instanceof Owl){
(box.animal as Owl).fly
}
但更好的方法是使用通用的 Box
:
class Box<T extends Animal> implements BoxInterface {
animal: T
constructor(animal: T) {
this.animal = animal
}
}
现在你可以写:
let box = new Box<Owl>(new Owl());
box.animal.sound()
box.animal.fly()
无论如何,正如 IMSoP 所说:如果您想应用特定于 [=18= 的方法,您必须在某些时候知道您拥有的是 Owl
].
你是对的,基础 class 合同保证了 最少 一组已知可用于其所有子类型的方法。
但是,TypeScript 在这里强制实施了一个额外的约束,即您应该只调用您知道 在您拥有的对象上可用的方法。
在这种情况下,您在编写代码时所知道的 box.animal.fly();
就是您有一个 Animal
;因此,你应该只调用 all 动物拥有的方法。
想想如果没有这张支票会发生什么:
let animal:Animal;
animal = new Snake();
animal.fly();
您会在运行时遇到某种错误。类型检查器的想法就是为你发现这种可能性,并让你写出"safe"这个意义上的代码。
这是一个面向对象的问题。当您声明某种类型的变量并为其赋值时,该值(某种)有两种类型:运行时类型和静态(编译时)类型。编译器考虑的类型是为该变量声明的类型(它是动物,而不是 Owl,因此不能有方法 fly()
)。这对覆盖方法有影响(它们可以通过静态或动态信息解决,具体取决于语言规范)。有关详细信息,请查看
What is the difference between statically typed and dynamically typed languages? https://en.wikipedia.org/wiki/Multiple_dispatch
所有其他答案均有效。 对于你的问题,你最好使用泛型
class Box<T extends Animal> {
constructor(public animal: T) { }
}
const box = new Box(new Owl())
box.animal.fly()