TypeScript 抽象类
一组相关的类常常共享同一套行为骨架:结构相似、实现不同。抽象类(abstract class)用来搭建这种骨架:它既能提供公共实现,又能用抽象方法强制子类补齐细节,让「继承它的类必然具备某些方法」成为编译期保证。
为什么需要抽象类
没有抽象类时,「子类必须实现某方法」只是口头约定,写漏了要等运行期才暴露。抽象类把约定升级成编译错误:漏实现就直接报错,代码更可靠。
定义抽象类与抽象方法
用 abstract 修饰的类不能直接 new,只能被继承;抽象方法只有签名、没有方法体:
abstract class Animal {
constructor(public name: string) {}
abstract makeSound(): void; // 只有签名,没有实现
}
// new Animal("x"); // 报错:无法创建抽象类的实例
抽象类相当于一份「施工图纸」,规定子类必须实现哪些部分。
子类必须实现抽象方法
继承抽象类的子类必须实现全部抽象方法,漏掉任何一个都会编译报错:
class Dog extends Animal {
makeSound(): void { // 必须实现,否则编译报错
console.log(this.name + " 汪汪叫");
}
}
const dog = new Dog("旺财");
dog.makeSound(); // 输出:旺财 汪汪叫
只要子类还残留未实现的抽象方法,它自己仍被视为抽象类,依然无法实例化。
抽象类里的公共实现
抽象类可以包含普通的具体方法,所有子类直接复用,也可以按需重写:
abstract class Shape {
abstract area(): number; // 子类各自计算面积
describe(): string { // 公共方法,子类共享
return "面积:" + this.area();
}
}
class Circle extends Shape {
constructor(private radius: number) {
super();
}
area(): number {
return Math.PI * this.radius * this.radius;
}
}
console.log(new Circle(2).describe()); // 输出:面积:12.566370614359172
子类只需实现 area,describe 这类通用逻辑在抽象类中写一次即可。
抽象类与接口的取舍
两者都能约束结构,侧重点不同:
| 对比项 | 抽象类 | 接口 |
|---|---|---|
| 具体实现 | 可以有已实现的方法 | 只有签名,由实现类补全 |
| 继承数量 | 单继承 | 可被 implements 多个 |
| 实例字段 | 可以有 | 只描述成员结构 |
| 适用场景 | 强相关的类族共享代码 | 跨类别的能力契约 |
需要复用代码、保存状态选抽象类;只需要「长什么样」的约定选接口。
小结:抽象类 = 公共实现 + 抽象方法约束,专为搭建类族骨架而生;与接口配合,就能把「代码复用」与「结构约定」拆开管理,让继承体系既灵活又可靠。