Skip to content

接口

在 TypeScript 中,接口是定义对象结构的强大方式。它不仅在面向对象编程中扮演着核心角色,也是描述数据形状的首选工具。

1. 面向对象中的接口

接口可以看作是比抽象类更纯粹的“契约”。它只声明结构(属性和方法),而不提供任何具体实现。

基本用法

通过 interface 定义结构,类使用 implements 关键字来实现接口:

typescript
interface Foo {
  name: string;
  get nameGetter(): string;
  method(name: string): string;
}

interface Bar {
  show(addr: string): string;
}

// 类可以实现多个接口
class Baz implements Foo, Bar {
  name = 'baz';
  get nameGetter(): string {
    return this.name;
  }
  method(name: string): string {
    return name;
  }
  show(addr: string): string {
    return addr;
  }
}

核心特性

  1. 关键字:类使用 implements 实现接口。
  2. 多实现:一个类可以同时实现多个接口,弥补了类单继承的局限。
  3. 无访问修饰符:接口中的成员默认为 public,不能使用 privateprotectedstatic
  4. 接口继承:接口之间可以使用 extends 继承,且支持多继承。

编译说明:抽象类在编译后会保留一个空的 JavaScript 类,而 interface 在编译后会被完全移除(类型擦除),不会产生任何运行时的代码。

2. 作为类型声明使用

对于纯前端开发而言,接口常被用作描述对象形状的工具,其心智负担比 type 更低。

typescript
interface User {
  readonly id: number; // 只读属性
  name: string;
  age?: number; // 可选属性
  show: (addr: string) => void;
}

const u: User = {
  id: 1,
  name: 'ruby',
  show(addr: string): void {
    console.log(addr);
  },
};

// u.id = 2; // Error: Cannot assign to 'id' because it is a read-only property.

3. 声明合并

这是 interface 区别于 type 的重要特性之一。TypeScript 会自动将多个同名的接口声明合并为一个。

typescript
interface User {
  readonly id: number;
  name: string;
}

interface User {
  age: number;
}

// 合并后的 User 接口同时拥有 id, name 和 age
const u: User = {
  id: 1,
  name: 'ruby',
  age: 18,
};

注意:合并时,同名属性的类型必须一致,否则会报错。

4. 接口的继承与扩展

接口可以通过 extends 继承其他接口或类型别名。

继承接口

typescript
interface Animal {
  name: string;
}

interface Dog extends Animal {
  bark(): void;
}

继承类型别名

typescript
type Action = {
  type: string;
};

interface UserAction extends Action {
  payload: any;
}

接口 vs 交叉类型

虽然可以使用 & (交叉类型) 模拟继承,但 extends 在性能和错误提示上通常更优:

typescript
// 接口方式 (推荐)
interface Person extends UserAction {
  sex: '男' | '女';
}

// 交叉类型方式
type PA = Person & Action & { sex: '男' | '女' };

5. 总结:Interface vs Type

特性InterfaceType Alias
定义对象支持支持
定义基本类型不支持支持
声明合并支持不支持
继承方式extends& (Intersection)
计算属性不支持支持

建议:在定义对象结构时,优先使用 interface;在定义联合类型、原始类型别名或需要复杂类型运算时,使用 type