type 和 interface 有什么区别?
简化版
interface 主要用于描述对象结构,支持声明合并和 extends;type 可以给任意类型起别名,能表达联合类型、交叉类型、条件类型等。对象建模两者都能用,公共可扩展 API 常用 interface,复杂类型组合常用 type。
详细版
interface:
interface User {
id: number;
name: string;
}
interface Admin extends User {
role: string;
}
type:
type ID = string | number;
type UserWithRole = User & { role: string };
差异:
- interface 可以重复声明并合并。
- type 不能重复声明同名别名。
- type 能表示联合、元组、基本类型别名、条件类型。
- interface 更适合面向对象式扩展。
实际项目里不要机械二选一,按表达能力和团队规范选择。
完整版教学
一、两者都能描述对象
interface A {
name: string;
}
type B = {
name: string;
};
这两段在对象结构描述上非常接近,所以面试不能只说“interface 定义对象,type 定义类型”,这不够准确。
二、声明合并是 interface 的特色
interface Window {
appVersion: string;
}
interface Window {
userId: string;
}
两个声明会合并。这对扩展第三方库类型、全局对象类型很有用。type 不允许同名重复定义。
三、type 的表达能力更广
type Status = 'success' | 'fail';
type Point = [number, number];
type Result<T> = T extends string ? string[] : T[];
这些复杂类型组合更适合 type。尤其是联合类型、条件类型、映射类型,基本都离不开 type。
四、工程选择建议
如果是库暴露出去的对象形状,希望用户能扩展,interface 更自然。如果是内部复杂类型计算、联合枚举、函数类型组合,type 更方便。
团队最好统一风格,不要同一类场景一半 type 一半 interface。
五、面试追问与工程落地
面试官常会追问“interface 能不能表示函数”。答案是可以,interface 可以描述调用签名:
interface Fn {
(x: number): string;
}
所以区别不在于“type 能写函数,interface 不能”,而在于 type 的组合表达能力更强,interface 的扩展和声明合并更自然。
还可能追问“类 implements 应该用哪个”。类可以 implements interface,也可以 implements 对象形状的 type;但如果是公共面向对象契约,interface 通常更语义化。类型组合、联合分支、工具类型结果则更适合 type。
工程里建议团队制定一致规范。比如“对象模型默认 interface,复杂类型别名默认 type”,或者“统一用 type”。最怕的是没有规则,导致同类场景混用,后续维护成本变高。
六、比较扩展冲突、开放性与发布边界
interface extends 与交叉类型都能组合对象形状,但冲突反馈不同。接口扩展遇到不兼容同名属性时通常在声明处直接报错;交叉类型可能继续生成一个属性为 never 的结果,把问题推迟到创建值时。公共 API 需要清晰报错时,这种差异值得考虑。
interface Base { id: string }
// interface Broken extends Base { id: number } // 声明处报错
type Mixed = { id: string } & { id: number }
type MixedId = Mixed['id'] // never
| 维度 | interface | type |
|---|---|---|
| 对象形状 | 支持 | 支持 |
| 声明合并 | 支持,可重新打开 | 不支持同名重复别名 |
| 联合、元组、条件类型 | 不能直接作为接口本体 | 支持 |
| 组合方式 | extends | &、` |
| 类实现对象契约 | 支持 | 对象形状别名也支持 |
假设库的接口被 3 个插件分别增加字段,声明合并可把 3 份扩展汇成一个类型;这也是全局增强和模块增强的基础。但开放性也有代价:无意的同名 interface 会被合并,第三方增强还可能让升级后的成员发生冲突。
选择依据不是“哪个更高级”,而是模型是否需要开放扩展,以及右侧是否需要联合、条件、映射等类型运算。
七、常见误区与追问
- 误区:interface 只能描述对象,type 只能描述非对象。 两者都能描述对象形状,差异主要在开放性和组合表达能力。
- 误区:interface 不能表示函数。 它可以声明调用签名、构造签名和属性,适合可扩展的函数对象契约。
- 误区:类只能 implements interface。 类也可实现可静态确定成员的对象类型别名,但不能实现尚未确定成员的联合类型。
- 追问:为什么声明合并既是能力也是风险? 它方便扩展库和全局类型,也可能因意外重名或不兼容成员导致远处报错。
- 追问:extends 和交叉类型冲突时表现一样吗? 不一样;接口扩展通常立即拒绝冲突,交叉组合可能产生 never 属性。
- 追问:公共库应该统一使用 interface 吗? 可扩展对象 API 常适合 interface,但联合、条件和映射结果仍需要 type,应按模型表达而非教条决定。
- 追问:type 为什么不能声明合并? 类型别名绑定的是一个完整类型表达式,同一作用域不能用重复别名重新打开它。
八、加强记忆
interface 像“可扩展的对象契约”,type 像“万能类型表达式”。对象结构两者都能写,声明合并选 interface,复杂组合选 type。
对象契约是否需要被重新打开决定开放性,是否需要联合和类型运算决定表达式能力,这两个问题足以指导大多数选择。