本文献给:
已掌握 TypeScript 接口定义、可选属性、只读属性、继承等知识的开发者。本文将讲解类如何通过 implements 关键字实现一个或多个接口,以及类实现接口与抽象类的区别,为后续面向对象编程篇章打下基础。
你将学到:
implements关键字的基本用法- 一个类实现多个接口
- 类实现接口时的类型检查规则
- 接口与抽象类的对比与选择
- 实现接口与继承类的组合使用
目录
- [一、implements 关键字](#一、implements 关键字)
-
- [1.1 类可以添加额外成员](#1.1 类可以添加额外成员)
- 二、实现多个接口
-
- [2.1 接口间的属性名冲突](#2.1 接口间的属性名冲突)
- [2.2 方法名冲突](#2.2 方法名冲突)
- 三、类实现接口时的类型检查
-
- [3.1 属性必须初始化](#3.1 属性必须初始化)
- [3.2 方法的参数和返回值必须匹配](#3.2 方法的参数和返回值必须匹配)
- [3.3 可选属性的处理](#3.3 可选属性的处理)
- 四、实现接口与继承类组合
-
- [4.1 接口可以继承类](#4.1 接口可以继承类)
- 五、接口与抽象类的对比
-
- [5.1 何时用接口](#5.1 何时用接口)
- [5.2 何时用抽象类](#5.2 何时用抽象类)
- 六、常见错误与注意事项
-
- [6.1 混淆 `extends` 和 `implements`](#6.1 混淆
extends和implements) - [6.2 实现接口时忘记处理可选属性](#6.2 实现接口时忘记处理可选属性)
- [6.3 接口定义的方法在类中实现时使用了错误的 `this` 类型](#6.3 接口定义的方法在类中实现时使用了错误的
this类型) - [6.4 私有字段冲突](#6.4 私有字段冲突)
- [6.5 实现多个接口时同名方法重载顺序](#6.5 实现多个接口时同名方法重载顺序)
- [6.1 混淆 `extends` 和 `implements`](#6.1 混淆
- 七、综合示例
- 八、小结
一、implements 关键字
接口描述了类的公共契约(public contract)。类可以使用 implements 关键字声明它必须实现某个接口的所有成员。
typescript
interface Drawable {
draw(): void;
color?: string; // 可选属性
}
class Circle implements Drawable {
draw() {
console.log("Drawing circle");
}
// color 是可选的,可以不实现
}
const c: Drawable = new Circle();
c.draw();
如果类没有完整实现接口定义的成员,TypeScript 会报错。
typescript
interface Point {
x: number;
y: number;
distance(): number;
}
class MyPoint implements Point {
x = 0;
y = 0;
// 缺少 distance 方法 ❌
}
1.1 类可以添加额外成员
实现接口的类可以拥有接口中未定义的额外属性和方法。
typescript
interface Animal {
name: string;
}
class Dog implements Animal {
name = "Buddy";
bark() { // 额外方法
console.log("woof");
}
}
二、实现多个接口
一个类可以实现多个接口,用逗号分隔。
typescript
interface Printable {
print(): void;
}
interface Serializable {
toJSON(): string;
}
class Report implements Printable, Serializable {
print() {
console.log("Printing report");
}
toJSON() {
return JSON.stringify({ content: "report" });
}
}
2.1 接口间的属性名冲突
如果两个接口有同名但类型不同的属性,类必须实现一个同时满足两种类型的成员。这通常意味着需要联合类型或无法满足。
typescript
interface A {
value: string;
}
interface B {
value: number;
}
class C implements A, B {
value: string | number = "hello"; // 联合类型可同时满足
}
如果类型完全不兼容(如 string 和 number 没有交集),则无法实现。
2.2 方法名冲突
如果两个接口有同名方法但签名不同,类中需要实现为重载。
typescript
interface Clickable {
click(): void;
}
interface Draggable {
click(x: number, y: number): void;
}
class UIElement implements Clickable, Draggable {
click(x?: number, y?: number): void {
if (x !== undefined && y !== undefined) {
console.log(`Dragged to ${x},${y}`);
} else {
console.log("Clicked");
}
}
}
三、类实现接口时的类型检查
3.1 属性必须初始化
接口中声明的属性,在类中必须被初始化(构造函数中赋值或声明时赋默认值),或标记为可选。
typescript
interface Config {
url: string;
timeout: number;
}
class HttpClient implements Config {
url: string;
timeout: number;
constructor(url: string) {
this.url = url;
this.timeout = 5000; // 初始化
}
}
3.2 方法的参数和返回值必须匹配
typescript
interface Formatter {
format(input: string): string;
}
class UpperFormatter implements Formatter {
format(input: number): number { // ❌ 参数类型不匹配
return input;
}
}
3.3 可选属性的处理
接口中的可选属性,类可以不实现。
typescript
interface Logger {
log(msg: string): void;
level?: string;
}
class ConsoleLogger implements Logger {
log(msg: string) {
console.log(msg);
}
// level 未实现,允许
}
四、实现接口与继承类组合
类可以同时继承一个父类并实现一个或多个接口。继承在前,implements 在后。
typescript
class BaseEntity {
id: number = 0;
}
interface Timestamped {
createdAt: Date;
updatedAt: Date;
}
class User extends BaseEntity implements Timestamped {
name: string;
createdAt: Date;
updatedAt: Date;
constructor(name: string) {
super();
this.name = name;
this.createdAt = new Date();
this.updatedAt = new Date();
}
}
4.1 接口可以继承类
如之前所学,接口可以继承类,然后由另一个类实现。但这要求实现类必须是该类的子类。
typescript
class Control {
private state: boolean;
}
interface SelectableControl extends Control {
select(): void;
}
class Button extends Control implements SelectableControl {
select() {}
}
// class Fake implements SelectableControl {} // ❌ 不是 Control 子类
五、接口与抽象类的对比
接口和抽象类都用于定义契约,但差异明显。
| 特性 | 接口 | 抽象类 |
|---|---|---|
| 实例化 | 不能 | 不能 |
| 实现方法体 | 不能(TS 接口只有声明) | 可以有具体方法 |
| 构造器 | 无 | 可以有 |
| 访问修饰符 | 所有成员隐含 public |
支持 private、protected |
| 多继承 | 一个类可实现多个接口 | 一个类只能继承一个抽象类 |
| 存储状态(字段) | 只能声明,不能初始化 | 可以声明并初始化字段 |
| 运行时存在 | 不存在(编译后消失) | 存在(编译为 JS 类) |
5.1 何时用接口
- 描述对象的结构(类似于"鸭子类型")
- 需要让一个类实现多个契约
- 与第三方库或 API 定义类型(轻量、无运行时开销)
- 类的实现完全不相关,只关心公共方法签名
5.2 何时用抽象类
- 需要提供部分默认实现
- 需要共享字段(状态)给子类
- 需要
protected成员或构造函数逻辑 - 需要运行时存在(如
instanceof检查)
六、常见错误与注意事项
6.1 混淆 extends 和 implements
类继承使用 extends,实现接口使用 implements。不能混用。
typescript
class A implements B // B 是接口
class C extends D // D 是类
6.2 实现接口时忘记处理可选属性
接口有可选属性,类可以不实现,但如果类中实现了该属性,类型必须匹配。
6.3 接口定义的方法在类中实现时使用了错误的 this 类型
方法签名中的 this 参数需要匹配。通常不需要显式写。
6.4 私有字段冲突
接口不能包含私有字段,因此无法强制类实现私有成员。这是接口与抽象类的关键区别。
6.5 实现多个接口时同名方法重载顺序
重载签名需要正确排列,实现签名必须兼容所有重载。
七、综合示例
typescript
// 定义两个接口
interface Eater {
eat(food: string): void;
}
interface Sleeper {
sleep(hours: number): void;
}
interface Reproducible {
reproduce(): void;
}
// 抽象类实现部分默认行为
abstract class Animal implements Eater, Sleeper {
name: string;
constructor(name: string) {
this.name = name;
}
eat(food: string) {
console.log(`${this.name} eats ${food}`);
}
sleep(hours: number) {
console.log(`${this.name} sleeps for ${hours} hours`);
}
abstract makeSound(): void; // 抽象方法
}
// 具体类
class Dog extends Animal implements Reproducible {
makeSound() {
console.log("Woof!");
}
reproduce() {
console.log(`${this.name} gives birth to puppies`);
}
// 额外方法
fetch() {
console.log(`${this.name} fetches the ball`);
}
}
class Cat extends Animal {
makeSound() {
console.log("Meow!");
}
// Cat 不实现 Reproducible
}
// 使用
const dog = new Dog("Buddy");
dog.eat("bone");
dog.sleep(8);
dog.makeSound();
dog.reproduce();
dog.fetch();
const cat = new Cat("Whiskers");
cat.eat("fish");
// 接口作为类型约束
function takeNap(animal: Sleeper) {
animal.sleep(1);
}
takeNap(dog);
takeNap(cat);
// 多个接口组合的场景:可序列化的用户
interface Serializable {
serialize(): string;
}
interface Identifiable {
id: number;
}
class User implements Identifiable, Serializable {
id: number;
name: string;
constructor(id: number, name: string) {
this.id = id;
this.name = name;
}
serialize(): string {
return JSON.stringify({ id: this.id, name: this.name });
}
}
const u = new User(1, "Alice");
console.log(u.serialize());
八、小结
| 概念 | 语法示例 | 说明 |
|---|---|---|
| 实现单接口 | class A implements B |
必须实现 B 的所有成员 |
| 实现多接口 | class A implements B, C |
必须实现 B 和 C 的所有成员 |
| 继承+实现 | class A extends B implements C |
先继承再实现 |
| 可选接口属性 | 类可以不实现,但如果实现必须类型匹配 | 提升灵活性 |
| 接口 vs 抽象类 | 接口纯契约(无实现),抽象类可含实现和状态 | 按需选择 |
觉得文章有帮助?别忘了:
👍 点赞 👍 -- 给我一点鼓励
⭐ 收藏 ⭐ -- 方便以后查看
🔔 关注 🔔 -- 获取更新通知
标签: #TypeScript #类实现接口 #implements #面向对象 #学习笔记 #前端开发