打字稿无法识别父类的属性?

时间:2017-01-10 19:50:20

标签: typescript

我有一个基本的遗产:

export abstract class Animal
{
     constructor() {

     }

     makeSound() {
         alert(this.sound);
     }
}

export class Dog extends Animal
{
     public sound: string = "Woof!";

     constructor() {
         super();
     }
}

const dog = new Dog;
dog.makeSound(); // Woof!

我在试图让上述代码段工作时出现问题。 Property prop does not exist on type A。但是,它确实存在于B上,并且由于它是公开的,因此A应该能够通过this.prop到达道具。

我尝试了以下内容:

  • 同上 - 它没有编译。 (A类不存在财产道具)
  • 如果我将public prop: any;添加到A,则prop会变为undefined而非Hello world
  • 如果我将public abstract prop: any;添加到A,则会发生同样的事情。

使用抽象类的整个继承点是共享this范围。

如何使用Typescript正确完成?

3 个答案:

答案 0 :(得分:7)

我同意JB Nizet。但您也可以将sound定义为抽象属性。这样你的基类就知道sound,所有扩展类都必须实现抽象属性sound

export abstract class Animal
{
    abstract sound: string; // Only change here, now your code works
    constructor() {

    }

    makeSound() {
        alert(this.sound);
    }
}

export class Dog extends Animal {
    public sound: string = "Woof!";

    constructor() {
        super();
    }
}

const dog = new Dog;
dog.makeSound(); // Woof!

定义抽象属性的能力来自TS 2.0:https://github.com/Microsoft/TypeScript/issues/4669

<强>更新

这种方法遇到的问题,参见注释,是抽象属性是在抽象基类的构造函数中使用的。这不起作用,因为在实例化对象之后,首先从派生类分配属性初始值。

这个问题有一个github issue,其解决方案是在抽象类的构造函数中访问抽象属性时出错。

答案 1 :(得分:1)

以下是您应该如何定义两个类:

javac

将属性放在Animal类中会告诉编译器所有动物都有声音。将声音作为超类构造函数的参数,可以清楚地表明所有子类在构造实例时都必须指定它们的声音。

还有其他可能的变体,但如果超类需要访问声音属性或某些getSound()方法,则此属性/方法应该存在于基类中。

答案 2 :(得分:1)

错误消息完全正确:prop上不存在A,因为它存在于B上。你可能来自JavaScript,你做的就是好的。 TypeScript和JavaScript之间的主要区别在于TypeScript是强类型的,而JavaScript是弱类型的。这种差异需要改变你的想法。

在像JavaScript这样的弱类型语言中,prop中不存在A并不重要。类型在运行时解析,如果您的实际实例有prop,一切都会好的。在静态(或强烈)类型的语言中,事物是不同的。类型在编译时强制执行,如果A未定义prop,则无法使用它。这就是强类型语言允许您定义抽象成员的原因:使它们可以在基类中访问,但实际上在派生类中定义rhem。

not all versions of TypeScript support abstract properties directly开始,此解决方案在任何情况下都应该有效:

export abstract class Animal
{
    get sound(): string { return getSound(); }
    protected abstract getSound(): string;
    constructor() {}
    makeSound(): void {
        console.log(this.sound);
    }
}

export class Dog extends Animal
{
    protected getSound: string { return "Woof!"; }

    constructor() {
        super();
    }
}

const b = new B;
B.makeSound();