🤔「`interface` 和 `type` 到底用哪个?」——几乎每个 TS 新手被这个选择灵魂拷问。

开场白:为什么又写这个话题?

「interface 和 type 到底用哪个?」------几乎每个 TS 新手在 StackOverflow 上都会刷到这条灵魂拷问。

官方文档只有一句 "they are largely equivalent" ,却藏了 10 多个细节坑:

有人因为用了 type 导致无法给第三方库"打补丁";有人因为滥用 interface 把编译器拖成"风扇狂魔";还有人把联合类型写进 interface 直接爆红。

1. 一句话先记住

interface 是"可扩展的结构性契约";type 是"类型层面的万能表达式"。

------先写 interface,做不到再请 type 出山,基本不会犯错。

2. 速查表(收藏级)

场景 推荐 例子
纯对象形状 interface interface User { name: string }
联合/元组 type `type Status = 'ok'
原始类型别名 type type ID = string
映射/条件类型 type type Partial<T> = { [K in keyof T]?: T[K] }
需要声明合并 interface 给 window 补属性
类 implements interface class Cat implements Animal
性能敏感巨型字典 interface 10w+ 键的 AST 节点
工具类型二次加工 type type CreateSlice<S> = Pick<Store<S>, 'getState'>

3. 10 维度硬核对比

3.1 语法能力

interface 只能描述对象、函数、类构造签名 ;
type 可以描述任意类型组合:联合、交叉、元组、映射、条件、模板字面量......

ts 复制代码
// 联合
type Pet = 'cat' | 'dog';
// 元组
type Coord = [number, number];
// 条件
type IsArray<T> = T extends any[] ? true : false;

→ 需要"组合/变形"时,直接上 type。

3.2 声明合并(Declaration Merging)

ts 复制代码
interface User { name: string; }
interface User { age: number; }   // 自动合并
type User = { name: string; };
type User = { age: number; };     // ❌ 重复标识符

给第三方库补类型、扩展 window、global 必须 interface。

3.3 同名属性冲突

ts 复制代码
interface A { x: number; }
interface B extends A { x: string; }  // ❌ 直接报错

type A = { x: number };
type B = A & { x: string };           // 不报错,但 x 成 never

interface 提前暴露错误;type 把问题推迟到使用点。

3.4 循环引用

ts 复制代码
interface Tree { left: Tree; right: Tree; }   // ✅ 直接递归

type Tree = { left: Tree; right: Tree; };     // ❌ 循环引用报错

想写链表、树、图,优先 interface。

3.5 编译性能

  • interface 采用名义+结构混合缓存,超大项目检查更快。
  • type 的深层交叉/联合可能触发指数展开 ,10w+ 节点场景差距明显。
    微软 TS Wiki 原话:

"Use interfaces until you need to use features from type aliases."

3.6 映射类型 & 工具类型

Partial、Record、Exclude、ReturnType... 全部用 type 实现,无法用 interface 表达。

3.7 可读性

ts 复制代码
type F = ((x: 'a') => 1) & ((x: 'b') => 2) extends infer R ? R : never;

这种"一行炸出 5 个关键字"的代码,用 interface 根本写不出来,也更容易把同事劝退。

→ 公共 API 优先 interface,内部黑魔法再包 type。

3.8 与 class 共舞

ts 复制代码
interface Clock { tick(): void; }
class A implements Clock { tick() {} }   // 语义贴合

implements 两者都支持,但 interface 更契合"契约"思想。

3.9 模块导出

无差异,都能 export。

3.10 官方未来路线

RFC 曾讨论"让 interface 支持联合",被否决;官方仍倾向 interface 做"结构契约"。

4. 实战决策树(复制即可)

text 复制代码
需要联合/元组/映射/条件/原始别名?
├─ 是 ──> 用 type
└─ 否 ──> 纯对象?
        ├─ 是 ──> 需要声明合并或 implements?
        │       ├─ 是 ──> interface
        │       └─ 否 ──> 可 interface 也可 type,**默认 interface**
        └─ 否 ──> type

5. 典型案例:写组件 Props

ts 复制代码
// 1. 先写契约
interface BaseProps {
  title: string;
  onClose: () => void;
}

// 2. 需要部分可选,再包一层 type
type DrawerProps = Partial<BaseProps> & {
  width?: number;
};

// 3. 导出给外部
export { DrawerProps };

既享受合并能力,又拿到工具类型的便利。

6. 小结:一句顺口溜

"对象先 interface,变形上 type;合并靠 interface,联合找 type。"

把这张速查表贴到仓库 Wiki,下次 Code Review 就不用再拉群辩论了。

如果这篇文章帮到了你,点个 ⭐ 再走呗~ 评论区聊聊:你们团队是"interface 党"还是"type 党**"?**

相关推荐
孔令飞21 分钟前
Go中指针引用Go中指针引用Go中指针引用Go中指针引用Go中指针引用Go中指针引用Go中指针引用Go中指针引用Go中指针引用Go中指针引用Go中指针引用Go中
前端
可乐鸡翅yeah_28 分钟前
hls.js 缓冲区参数 maxBufferLength、maxBufferSize 通俗讲解与业务调参
开发语言·javascript·ios·音视频·safari·m3u8
溪语流沙34 分钟前
【Web全栈进阶】PostgreSQL上手:Docker跑库 + 把早报站从SQLite迁过去
前端·docker·postgresql
IT_陈寒40 分钟前
SpringBoot自动配置的坑:你以为的捷径可能是弯路
前端·人工智能·后端
paopaokaka_luck40 分钟前
高校社团管理(AI辅助任务分配、协同过滤算法推荐、ECharts数据可视化、活动参与闭环、校园交流与反馈、器材借还管理)
java·前端·javascript·spring boot·数据分析·echarts
500841 小时前
React Native for OpenHarmony 实战:三方库 react-native-volume-control 的鸿蒙化适配指南
javascript·react native·react.js·electron·harmonyos
薛一半1 小时前
React-Redux三重优化实战揭秘
javascript·vue.js·react.js
Dovis(誓平步青云)1 小时前
导览音频切换太快,旧讲解不能覆盖新展品
android·前端·javascript·ecmascript·音视频·宠物
福兮说12 小时前
设计稿是 #4A7C6F,页面量出来是 #4B7C6F:HEX、HSL、透明度、canvas 来回转的七个坑
前端·javascript·css·canvas
AI情绪识别开源12 小时前
HFpEF 心房-心室耦联效率无创监测方向(AVCEI)
typescript·laravel·perl