TypeScript 类型定义:接口与类型别名
TypeScript 提供了两种主要方式来定义数据的类型:接口和类型别名。虽然两者在许多情况下可以互换使用,但它们在底层机制和适用场景上存在关键差异。掌握这些差异有助于编写更规范、更易维护的代码。
1. 定义基础对象结构
定义一个对象的形状时,interface 和 type 的写法非常相似。
使用 interface 关键字来描述对象。
interface User {
name: string;
age: number;
}
const user1: User = { name: "Alice", age: 25 };
使用 type 关键字配合等号 = 来定义类型别名。
type User = {
name: string;
age: number;
};
const user2: User = { name: "Bob", age: 30 };
对于纯对象定义,两者效果一致。选择 interface 通常更符合传统面向对象编程的习惯。
2. 处理联合类型、元组与基本类型
type 别名的功能比 interface 更广泛,它不仅限于对象。
定义联合类型时,必须使用 type。
type ID = string | number;
定义元组类型时,必须使用 type。
type Coordinate = [number, number];
定义基本类型的别名时,必须使用 type。
type Name = string;
interface 无法直接表示上述三种情况,它只能描述对象的结构。
3. 扩展类型
当需要基于现有类型创建新类型时,两者的语法不同。
使用 extends 关键字来扩展 interface。
interface Animal {
name: string;
}
interface Dog extends Animal {
breed: string;
}
使用 交叉运算符 & 来组合 type。
type Animal = {
name: string;
};
type Dog = Animal & {
breed: string;
};
虽然语法不同,但结果都是新类型包含了旧类型的所有属性。注意:interface 也可以扩展 type,只要该 type 是对象类型的表示;同样,type 也可以通过 & 操作符包含 interface。
4. 声明合并
这是 interface 与 type 最重要的区别之一。
多次声明同名的 interface,TypeScript 会自动将它们合并为一个接口。
interface Box {
width: number;
}
interface Box {
height: number;
}
const box: Box = { width: 10, height: 20 }; // 合并成功
重复声明同名的 type 别名会导致报错。
type Box = {
width: number;
};
// 报错:重复标识符 'Box'
type Box = {
height: number;
};
利用声明合并特性来扩展第三方库的类型定义是 interface 的典型应用场景。
5. 决策指南
根据具体需求选择合适的定义方式。下表总结了在不同场景下的最佳实践。
| 场景需求 | 推荐使用 | 理由 |
|---|---|---|
| 定义对象的形状 | interface |
语义更清晰,支持声明合并,便于扩展 |
定义联合类型 (A \| B) |
type |
interface 不支持联合类型 |
定义元组 ([string, number]) |
type |
interface 不支持元组 |
定义基本类型别名 (如 type Str = string) |
type |
interface 不支持基本类型 |
映射类型 (如 Partial) |
type |
通用工具类型通常基于 type 实现 |
| 需要合并同名声明 | interface |
唯一支持声明合并的特性 |
| 复杂的类型组合(函数、交叉、联合混合) | type |
表达能力更强,灵活性最高 |
记住一条通用原则:优先使用 interface 来定义对象和 API 的形状,因为它不仅语义直观,还能在代码库演进时提供更好的可扩展性。只有当需要使用联合类型、元组或其他 interface 无法表达的高级类型时,才切换使用 type。

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