文章目录

TypeScript 接口:interface 定义与实现

发布于 2026-04-02 04:14:26 · 浏览 18 次 · 评论 0 条

TypeScript 接口:interface 定义与实现

TypeScript 的 interface 是定义对象“形状”的核心工具。它不生成任何运行时代码,仅在编译阶段进行类型检查,确保你使用的对象拥有预期的属性和方法。


1. 基础接口定义

创建一个最简单的接口,只需使用 interface 关键字后跟接口名和花括号:

interface User {
  name: string;
  age: number;
}

这个 User 接口规定:任何符合该类型的对象必须包含一个名为 name 的字符串属性和一个名为 age 的数字属性。

声明一个变量并指定其类型为 User

const person: User = {
  name: "张三",
  age: 28
};

如果遗漏任一属性,或属性类型不符(如 age: "28"),TypeScript 编译器会报错。


2. 可选属性与只读属性

可选属性

在属性名后添加问号 ?,表示该属性可以不存在:

interface Car {
  brand: string;
  color?: string; // 可选
}

现在你可以这样使用:

const myCar: Car = { brand: "Toyota" }; // 合法,color 可省略
const yourCar: Car = { brand: "Honda", color: "blue" }; // 也合法

只读属性

在属性名前加 readonly,表示该属性在对象创建后不可修改:

interface Point {
  readonly x: number;
  readonly y: number;
}

尝试修改只读属性会触发错误:

const origin: Point = { x: 0, y: 0 };
// origin.x = 1; // 错误!Cannot assign to 'x' because it is a read-only property.

注意:readonly 是编译时约束,不阻止运行时通过类型断言绕过。但它能有效防止意外修改。


3. 函数类型与方法定义

接口不仅能描述数据结构,还能描述函数签名。

描述函数类型

interface GreetFunction {
  (name: string): string;
}

这表示一个接受 string 参数并返回 string 的函数。实现如下:

const sayHello: GreetFunction = (name) => `你好,${name}!`;
```

### 在对象中定义方法

更常见的是在对象接口中直接声明方法:

```typescript
interface Calculator {
  add(a: number, b: number): number;
  subtract(a: number, b: number): number;
}
```

**创建**一个符合该接口的对象:

```typescript
const calc: Calculator = {
  add(a, b) {
    return a + b;
  },
  subtract(a, b) {
    return a - b;
  }
};
```

注意:方法定义中参数类型可省略(因接口已声明),但返回类型建议保留以增强可读性。

---

## 4. 实现接口:class 与 implements

使用 `implements` 关键字让类遵循某个接口的契约。

**定义**一个接口:

```typescript
interface Animal {
  name: string;
  makeSound(): void;
}
```

**创建**一个类并实现该接口:

```typescript
class Dog implements Animal {
  name: string;

  constructor(name: string) {
    this.name = name;
  }

  makeSound() {
    console.log("汪汪!");
  }
}
```

关键点:
- 类必须**显式声明**所有接口要求的属性(如 `name: string`)。
- 必须**提供**所有接口方法的具体实现。
- 可以添加接口未要求的额外属性或方法。

一个类可以同时实现多个接口:

```typescript
interface Flyable {
  fly(): void;
}

class Bird implements Animal, Flyable {
  name: string;

  constructor(name: string) {
    this.name = name;
  }

  makeSound() {
    console.log("啾啾!");
  }

  fly() {
    console.log("飞起来啦!");
  }
}
```

---

## 5. 接口继承与合并

### 接口继承

使用 `extends` 让一个接口基于另一个接口扩展:

```typescript
interface Shape {
  color: string;
}

interface Circle extends Shape {
  radius: number;
}
```

现在 `Circle` 接口包含 `color` 和 `radius` 两个属性。**使用**时:

```typescript
const circle: Circle = {
  color: "red",
  radius: 5
};
```

支持多重继承:

```typescript
interface Drawable {
  draw(): void;
}

interface Resizable {
  resize(factor: number): void;
}

interface UIElement extends Drawable, Resizable {
  id: string;
}
```

`UIElement` 同时拥有 `draw()`、`resize()` 方法和 `id` 属性。

### 接口自动合并

如果在同一作用域内**多次声明**同名接口,TypeScript 会自动将其成员合并:

```typescript
interface Box {
  width: number;
}

interface Box {
  height: number;
}
```

最终 `Box` 接口等价于:

```typescript
interface Box {
  width: number;
  height: number;
}
```

这一特性常用于为第三方库扩展类型定义(如在 `.d.ts` 文件中补充缺失的属性)。

---

## 6. 索引签名与任意属性

当对象的属性名不确定,但值类型固定时,使用索引签名。

### 字符串索引签名

```typescript
interface StringArray {
  [index: number]: string;
}
```

这表示用数字索引访问时返回字符串,适用于类数组对象。

更常用的是对象形式的任意属性:

```typescript
interface AnyObject {
  [key: string]: any;
}
```

现在可以给 `AnyObject` 添加任意字符串键的属性:

```typescript
const obj: AnyObject = {};
obj.foo = 123;
obj.bar = "hello";
```

> 警告:过度使用 `[key: string]: any` 会削弱类型安全性,应尽量避免。

### 约束任意属性类型

若希望所有额外属性都符合特定类型,可结合已知属性使用:

```typescript
interface Options {
  timeout: number;
  retries: number;
  [key: string]: string | number; // 其他属性只能是 string 或 number
}
```

这样既保留了明确的配置项,又允许灵活扩展。

---

## 7. 与类型别名 type 的区别

TypeScript 还有 `type` 别名,也能定义对象形状。两者主要区别如下:

  
| 特性 | `interface` | `type` |
| :--- | :---: | :---: |
| 可扩展(合并) | ✅ 自动合并同名接口 | ❌ 不可重复定义 |
| 支持计算属性 | ❌ 有限支持 | ✅ 完全支持(如联合类型、元组) |
| 实现(implements) | ✅ 可被 class 实现 | ✅ 可被 class 实现 |
| 描述原始类型 | ❌ 不能 | ✅ 可以(如 `type ID = string`) |

**优先使用 `interface`**,除非你需要:
- 定义联合类型(如 `type Status = "success" | "error"`)
- 使用元组(如 `type Point = [number, number]`)
- 映射类型或条件类型

---

## 8. 实战示例:API 响应结构定义

假设你调用一个用户信息 API,返回如下结构:

```json
{
  "id": 101,
  "username": "alice",
  "email": "alice@example.com",
  "profile": {
    "bio": "Frontend developer",
    "avatar": "https://example.com/avatar.jpg"
  }
}
```

**定义**对应的接口:

```typescript
interface UserProfile {
  bio: string;
  avatar: string;
}

interface UserResponse {
  id: number;
  username: string;
  email: string;
  profile: UserProfile;
}
```

**使用**时配合 `fetch`:

```typescript
async function fetchUser(id: number): Promise<UserResponse> {
  const res = await fetch(`/api/users/${id}`);
  return res.json();
}

fetchUser(101).then(user => {
  console.log(user.profile.bio); // 类型安全,自动补全
});

这种分层接口设计让代码清晰、可维护,并在数据结构变化时快速暴露问题。


定义接口时始终从使用者角度出发,关注“需要什么”,而非“有什么”。通过 interface 明确契约,你的 TypeScript 代码将获得更强的健壮性和可读性。

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文