这是一个在 TypeScript 社区中争论已久的经典问题。
在 TypeScript 的早期版本中,它们的区别很大。但随着 TS 的更新(尤其是 TS 2.x 以后),它们的功能重合度已经高达 90%。
简单来说:interface 是“传统的面向对象接口”,侧重于描述对象的形状;type 是“类型别名”,侧重于定义各种组合类型。
以下是它们的核心区别,按重要性排序:
1. 核心区别:声明合并 (Declaration Merging)
这是两者最大、最本质的区别。
interface支持合并: 如果你定义了两个同名的interface,TS 会自动把它们合并成一个。这在为第三方库(如window对象或jquery)打补丁时非常有用。type不支持合并: 如果重复定义同名type,TS 会直接报错。
TypeScript
// ✅ Interface: 自动合并
interface User {
name: string;
}
interface User {
age: number;
}
const user: User = {
name: "Gemini",
age: 18 // 必须包含两个属性
};
// ❌ Type: 报错 "Duplicate identifier 'Admin'"
type Admin = {
name: string;
};
type Admin = { // Error!
age: number;
};
2. 表达能力 (Capabilities)
type 的能力比 interface 更广泛,它像一把瑞士军刀。
interface只能定义: 对象 (Object)、函数 (Function)。type可以定义: 对象、函数,以及基本类型别名、联合类型、元组等。
只有 type 能做的事:
TypeScript
// 1. 基本类型别名
type ID = string | number;
// 2. 联合类型 (Union Types)
type Status = "pending" | "success" | "failed";
// 3. 元组 (Tuples)
type Point = [number, number];
// 4. 复杂的映射类型 (Mapped Types)
type Keys = keyof User;
如果你需要用到 | (或) 或者 & (与) 这种逻辑操作符,通常只能用 type。
3. 扩展方式 (Extends vs Intersection)
虽然两者都能扩展,但语法和语义略有不同。
interface使用extends(继承): 语义更强,表示“我是它的一种”。TS 会检查兼容性。type使用&(交叉类型): 表示“把这两个拼起来”。
TypeScript
// Interface 继承
interface Animal {
name: string;
}
interface Bear extends Animal {
honey: boolean;
}
// Type 交叉
type AnimalType = {
name: string;
};
type BearType = AnimalType & {
honey: boolean;
};
总结对比表
最佳实践:我该用哪个?
在现代 TypeScript 开发(尤其是 React/Vue 项目)中,业界的共识正在发生微妙的变化。
编写库 (Library) 或定义公共 API 时:
👉 优先使用
interface。原因: 允许使用者通过声明合并(Declaration Merging)来扩展你的类型。例如,用户可能想给你的
Config对象加一个自定义属性。
编写应用程序 (Application) 业务代码时:
👉 优先使用
type(很多团队现在的规范)。原因:
type更灵活,且防止意外的声明合并。特别是在定义 React 组件的Props时,type Props = { ... }看起来更直观,且容易与联合类型组合。
简单粗暴原则:
先用
interface来描述对象(为了遵循 OOP 直觉)。如果发现
interface搞不定(比如需要联合类型|),再立马换成type。