
我们已经知道，接口（Interfaces）是 TypeScript 中用以定义对象“契约”的强大工具。它为我们的代码带来了结构和秩序。现在，我们来探讨一个能将这种结构化能力提升到新层次的特性——**扩展接口**。

在构建复杂的应用时，我们的数据模型之间往往存在着天然的层次关系。例如，一个“管理员”首先是一个“用户”；一个“圆”首先是一个“形状”。我们不希望每次定义一个特殊类型时，都从头复制一遍基础类型的全部属性。这不仅繁琐，而且极易导致不一致。

扩展接口正是为了解决这个问题而生。它允许一个接口继承另一个接口的属性，从而实现代码的复用，并建立起清晰的类型继承体系。

### 核心语法：`extends` 关键字

扩展接口的语法非常直观，我们使用 `extends` 关键字来声明一个接口是基于另一个接口构建的。

让我们从一个简单的例子开始。假设我们有一个基础的 `Person` 接口：

```typescript
interface Person {
  name: string;
  age: number;
}
```

现在，我们需要定义一个 `Employee`（员工）接口。一个员工首先是一个人，所以他/她拥有 `name` 和 `age` 属性。此外，员工还有自己独特的属性，比如 `employeeId` 和 `department`。

我们可以这样定义 `Employee` 接口：

```typescript
interface Employee extends Person {
  employeeId: string;
  department: string;
}
```
通过 `extends Person`，`Employee` 接口自动“吸收”了 `Person` 接口的所有成员。现在，一个 `Employee` 类型的对象必须同时满足 `Person` 和 `Employee` 自身定义的全部属性：

```typescript
const employee: Employee = {
  name: "John Doe",
  age: 35,
  employeeId: "E12345",
  department: "Engineering",
};

// const invalidEmployee: Employee = { name: "Jane Doe", age: 30 };
// 编译时错误: Property 'employeeId' and 'department' are missing.
```
这种方式完美地遵循了 **DRY (Don't Repeat Yourself)** 原则，让我们的类型定义变得既简洁又易于维护。

### 扩展接口带来的优势

#### 1. 类型兼容性

扩展接口建立了一种明确的“is-a”（是一个）关系。在我们的例子中，`Employee` “is a” `Person`。这种关系使得类型系统具有了强大的兼容性：**任何期望接收父接口类型（`Person`）的地方，都可以安全地传入一个子接口类型（`Employee`）的实例。**

```typescript
function greetPerson(person: Person): void {
  console.log(`Hello, ${person.name}! You are ${person.age} years old.`);
}

const employee: Employee = { /* ... */ };

// 完全合法！因为 employee 也是一个 Person
greetPerson(employee); 
```
这个特性是多态（Polymorphism）的基础，它让我们可以编写出更通用、更灵活的函数。

#### 2. 建立清晰的层次结构

通过 `extends`，我们可以构建出反映真实世界逻辑的类型层次。这使得我们的数据模型更加清晰，代码的意图也更容易被理解。

```typescript
interface Shape {
  color: string;
}

interface Square extends Shape {
  sideLength: number;
}

interface Circle extends Shape {
  radius: number;
}
```
在这里，`Square` 和 `Circle` 都共享了 `Shape` 的 `color` 属性，同时又定义了各自独有的属性，形成了一个清晰的继承树。

### 扩展多个接口

TypeScript 的接口还支持从多个父接口进行扩展，这让我们可以将不同维度的能力组合到一个新的接口中。语法是在 `extends` 关键字后用逗号分隔多个父接口。

假设我们有两个描述行为的接口：`Clickable` 和 `Draggable`。

```typescript
interface Clickable {
  onClick(event: MouseEvent): void;
}

interface Draggable {
  onDrag(event: DragEvent): void;
}
```

现在，我们想创建一个 `Button` 组件的接口，它既可以被点击，也可以被拖动。我们可以让 `Button` 接口同时扩展 `Clickable` 和 `Draggable`：

```typescript
interface Button extends Clickable, Draggable {
  label: string;
}

const myButton: Button = {
  label: "Submit",
  onClick: (e) => { /* ... */ },
  onDrag: (e) => { /* ... */ },
};
```
通过这种方式，`Button` 接口聚合了来自多个源头的能力，形成了一个强大的复合契约。这种模式在前端组件设计中非常常见，常被称为“混入 (Mixin)”模式。

### 总结

扩展接口是 TypeScript 中组织和复用类型定义的核心机制。它不仅仅是语法的便利，更是一种构建健壮、可维护数据模型的设计思想。

*   **`extends` 关键字** 允许一个接口继承另一个或多个接口的属性，实现了代码的复用。
*   它建立了清晰的 **类型层次** 和 **兼容性**，使得子接口的实例可以被用在任何需要父接口的地方。
*   通过 **扩展多个接口**，我们可以灵活地将不同的功能“混入”到一个新的类型定义中。

当你开始设计应用的类型系统时，请时刻思考类型之间的关系。如果一个类型是另一个类型的特殊化或功能组合，那么扩展接口无疑是你手中最得力的工具，它将帮助你构建出既优雅又坚固的“类型大厦”。

