在TypeScript中声明抽象方法

Voj*_*ěch 171 typescript

我试图弄清楚如何在TypeScript中正确定义抽象方法:

使用原始继承示例:

class Animal {
    constructor(public name) { }
    makeSound(input : string) : string;
    move(meters) {
        alert(this.name + " moved " + meters + "m.");
    }
}

class Snake extends Animal {
    constructor(name) { super(name); }
    makeSound(input : string) : string {
        return "sssss"+input;
    }
    move() {
        alert("Slithering...");
        super.move(5);
    }
}
Run Code Online (Sandbox Code Playgroud)

我想知道如何正确定义方法makeSound,因此它是键入的并且可能被覆盖.

此外,我不知道如何正确定义protected方法 - 它似乎是一个关键字,但没有效果,代码将无法编译.

Fen*_*ton 254

name物业标记为protected.这是在TypeScript 1.3中添加的,现在已经确立.

makeSound方法被标记为abstract,类.你不能直接实例化一个Animalnow,因为它是抽象的.这是TypeScript 1.6的一部分,现在正式上线.

abstract class Animal {
    constructor(protected name: string) { }

    abstract makeSound(input : string) : string;

    move(meters) {
        alert(this.name + " moved " + meters + "m.");
    }
}

class Snake extends Animal {
    constructor(name: string) { super(name); }

    makeSound(input : string) : string {
        return "sssss"+input;
    }

    move() {
        alert("Slithering...");
        super.move(5);
    }
}
Run Code Online (Sandbox Code Playgroud)

模仿抽象方法的旧方法是在任何人使用它时抛出错误.一旦TypeScript 1.6登陆您的项目,您就不需要再这样做了:

class Animal {
    constructor(public name) { }
    makeSound(input : string) : string {
        throw new Error('This method is abstract');
    }
    move(meters) {
        alert(this.name + " moved " + meters + "m.");
    }
}

class Snake extends Animal {
    constructor(name) { super(name); }
    makeSound(input : string) : string {
        return "sssss"+input;
    }
    move() {
        alert("Slithering...");
        super.move(5);
    }
}
Run Code Online (Sandbox Code Playgroud)


Tid*_*ddo 19

如果你更进一步地回答Erics,你实际上可以创建一个相当不错的抽象类实现,完全支持多态和从基类调用实现方法的能力.让我们从代码开始:

/**
 * The interface defines all abstract methods and extends the concrete base class
 */
interface IAnimal extends Animal {
    speak() : void;
}

/**
 * The abstract base class only defines concrete methods & properties.
 */
class Animal {

    private _impl : IAnimal;

    public name : string;

    /**
     * Here comes the clever part: by letting the constructor take an 
     * implementation of IAnimal as argument Animal cannot be instantiated
     * without a valid implementation of the abstract methods.
     */
    constructor(impl : IAnimal, name : string) {
        this.name = name;
        this._impl = impl;

        // The `impl` object can be used to delegate functionality to the
        // implementation class.
        console.log(this.name + " is born!");
        this._impl.speak();
    }
}

class Dog extends Animal implements IAnimal {
    constructor(name : string) {
        // The child class simply passes itself to Animal
        super(this, name);
    }

    public speak() {
        console.log("bark");
    }
}

var dog = new Dog("Bob");
dog.speak(); //logs "bark"
console.log(dog instanceof Dog); //true
console.log(dog instanceof Animal); //true
console.log(dog.name); //"Bob"
Run Code Online (Sandbox Code Playgroud)

由于Animal类需要实现IAnimal它,因此如果Animal没有抽象方法的有效实现,就不可能构造类型的对象.请注意,要使多态性工作,您需要传递实例IAnimal,而不是Animal.例如:

//This works
function letTheIAnimalSpeak(animal: IAnimal) {
    console.log(animal.name + " says:");
    animal.speak();
}
//This doesn't ("The property 'speak' does not exist on value of type 'Animal')
function letTheAnimalSpeak(animal: Animal) {
    console.log(animal.name + " says:");
    animal.speak();
}
Run Code Online (Sandbox Code Playgroud)

与Erics答案的主要区别在于"抽象"基类需要接口的实现,因此无法在其自身实例化.