在 TypeScript 中扩展与实现纯抽象 class

Extending vs. implementing a pure abstract class in TypeScript

假设我有一个纯抽象class(即没有任何实现的抽象class):

abstract class A {
    abstract m(): void;
}

就像在 C# 和 Java 中一样,我可以 扩展 抽象 class:

class B extends A {
    m(): void { }
}

但是不像在C#和Java,我也可以实现抽象class:

class C implements A {
    m(): void { }
}

classes BC 有何不同?我为什么要选择一个而不是另一个?

(目前,TypeScript handbook and language specification 不涵盖摘要 classes。)

implements关键字把Aclass当作一个接口,也就是说C必须实现A[=26中定义的所有方法=],无论他们是否在 A 中有实现。 C.

中也没有调用超级方法

extends 的行为更像您对关键字的期望。您只需实现抽象方法,超级调用是 available/generated.

我想在抽象方法的情况下,它没有什么区别。但是你很少有一个只有抽象方法的class,如果你这样做的话,最好把它转换成一个接口 .

您可以通过查看生成的代码轻松地看到这一点。我做了一个 playground 的例子 here.

在您提供的扩展示例中,您实际上并未向 class 添加任何新内容。所以它没有任何扩展。尽管不进行任何扩展是有效的 Typescript,但在我看来,在这种情况下 'implements' 会更合适。但归根结底,它们是等价的。

上构建,如果您 扩展 一个抽象 class,您必须在子 class 中调用 super() ] 的构造函数。如果你实现抽象class,你不必调用super()(但你必须实现抽象[=21=中声明的所有方法],包括私有方法)。

如果您想创建一个用于测试的模拟 class 而不必担心原始 class 的依赖项和构造函数。

我被带到这里是因为我刚刚问自己同样的问题,在阅读答案时我发现这个选择也会影响 instanceof 运算符。

由于抽象 class 是一个实际值,它被发送到 JS,当子class 扩展它时,它可以用于运行时检查。

abstract class A {}

class B extends A {}

class C implements A {}

console.log(new B() instanceof A) // true
console.log(new C() instanceof A) // false

我发现使用纯 abstract class ( A ) 然后使用 implements 似乎是一种注释有关您可能想要在合同中强制执行的访问权限的信息的方法,但接口或基础 class 扩展不会

例如,这对我有用(摘自Svelte-Kit程序,仅供参考)

abstract class AudioEngine {
    protected static ctx: AudioContext;
    protected static setState(s: string) { };
}

class Elementary implements AudioEngine {

constructor(ctx: AudioContext) {
    this.ctx = ctx;
};

ctx: AudioContext

protected setState(newState: string) {
        this.status.set(Sound[newState])
        return this.getState()
    };