打字稿手册中的继承示例

inheritance example from typescript manual

阅读 typescript manual 中的示例:

class Animal {
    name:string;
    constructor(theName: string) { this.name = theName; }
    move(meters: number = 0) {
        alert(this.name + " moved " + meters + "m.");
    }
}

class Snake extends Animal {
    constructor(name: string) { super(name); }
    move(meters = 5) {
        alert("Slithering...");
        super.move(meters);
    }
}

class Horse extends Animal {
    constructor(name: string) { super(name); }
    move(meters = 45) {
        alert("Galloping...");
        super.move(meters);
    }
}

var sam = new Snake("Sammy the Python");
var tom: Animal = new Horse("Tommy the Palomino");

sam.move();
tom.move(34);

问题是关于行 var tom: Animal = new Horse("Tommy the Palomino");:

在上面的例子中,Animal是一个superclass(也叫base classHorseSnake 父级 class)。相应地,HorseSnakesubclasses派生classesAnimal.

当您声明子class时:

class Snake extends Animal
...
class Horse extends Animal

您是在告诉编译器任何每个 Snake 和每个 Horse 实际上也是一个 Animal。这使得 Animal 成为程序 "world" 中更广泛的类别。 SnakeHorse 继承 Animal 的属性,但他们可以更改它们(and/or 添加一些他们自己的)变得更 专业化 .

  • tom 的声明告诉编译器该变量将接受任何 Animal。正如我们之前看到的,Horse 是一个 Animal,所以编译器让它通过。

  • 因此,他们说明了这样一个事实,即无论何时在任何表达式中期望 superclass 的成员,其任何 subclasses 的成员都是可接受的。这称为 协方差.

  • 从最字面的意义上讲,没有进化或退化。行

    tom: Animal = new Horse("Tommy the Palomino");

    首先导致创建一个新的 Horse 对象。然后将对象分配给变量 tom,但此分配 不会 更改对象的属性。如果你 运行 这个例子,你会看到调用 horse.move() 实际上调用了方法 moveHorse 版本,它会报告 "Tommy the Palomino moved 45m"。

    Horse 分配给 Animal 的唯一可辨别的副作用是变量,作为最通用的类​​型,不知道 [=13= 的任何特殊属性].它只知道所有 Animal 的共同点。假设 Horse 是这样声明的:

    class Horse extends Animal {
        constructor(name: string) { super(name); }
        move(meters = 45) {
            //...
        }
        swat_fly() { /* ... */ }
    }
    

    您将无法拨打 tom.swat_fly()。如果你愿意,你要么需要类型转换 tom(像这样:(<Horse>tom).swat_fly()),要么将其声明为 Horse 而不是 Animal。但是我重申:对象的属性没有改成superclass的.

  • 所以不,这不是打字错误:)