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

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

interfacetype 到底用哪个?」------几乎每个 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; };     // ❌ 重复标识符

给第三方库补类型、扩展 windowglobal 必须 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 映射类型 & 工具类型

PartialRecordExcludeReturnType... 全部用 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 党**"?**

相关推荐
岁月宁静3 小时前
AI 时代,每个程序员都该拥有个人提示词库:从效率工具到战略资产的蜕变
前端·人工智能·ai编程
行走在顶尖3 小时前
代码管理
前端
_AaronWong3 小时前
Electron IPC 自动化注册方案:模块化与热重载的完美结合
前端·electron·node.js
我的div丢了肿么办3 小时前
vue3使用h函数如何封装组件和$attrs和props的区别
前端·javascript·vue.js
答案answer3 小时前
你不知道的Three.js性能优化和使用小技巧
前端·性能优化·three.js
自由的疯3 小时前
java调chrome浏览器显示网页
java·前端·后端
小白而已3 小时前
协程&挂起&恢复
前端
Mintopia3 小时前
单体 vs 微服务:当 Next.js 长成“巨石阵”以后 🪨➡️🧩
前端·后端·全栈
吃饺子不吃馅3 小时前
大家都在找的手绘/素描风格图编辑器它它它来了
前端·javascript·css