优先用 interface 描述对象契约(如实体、props),支持 implements/extends 和声明合并;type 适用于联合类型、字面量、元组、函数类型等更广场景,不支持继承与合并。

在 JavaScript 项目中引入 TypeScript 后,接口(interface)和类型别名(type)是规范数据结构最常用、也最关键的两种方式。它们不是语法糖,而是类型系统的骨架——用对了,能提前拦截大量运行时错误;用混了,反而增加维护成本。
什么时候该用 interface
接口专为“对象契约”而生,适合描述你期望从 API、组件 props、配置项或返回值中拿到的结构化数据。
- 定义用户、订单、菜单项这类有明确字段和语义的实体时,优先写
interface - 需要被类
implements或其他接口extends时,只能用interface - 多个同名
interface声明会自动合并(声明合并),适合分散定义同一结构(如全局扩展Window) - 属性可选用
?,只读用readonly,动态键用索引签名[key: string]: number
示例:
interface User {id: number;
name: string;
email?: string;
readonly createdAt: Date;
}
什么时候该用 type
类型别名更像“类型快捷方式”,它不局限于对象,能表达更广的类型场景。
立即学习“Java免费学习笔记(深入)”;
- 定义联合类型(
type Status = 'active' | 'inactive')、字面量类型、元组(type Point = [number, number])必须用type - 给函数类型起名(
type ClickHandler = (e: MouseEvent) => void)更自然 - 需要递归引用(如树形结构
type TreeNode = { value: string; children?: TreeNode[] })时,type更直接 - 避免重复写长类型表达式,比如
type ApiResponse<t> = { data: T; success: boolean }</t>
注意:type 不能被 implements 或 extends,也不支持声明合并。
别在对象类型上硬套“非此即彼”
实际开发中,接口和类型别名在纯对象定义上经常可以互换,但风格要统一:
- 团队约定:所有业务模型(User、Product、ApiResponse)用
interface;所有状态枚举、工具类型、泛型包装用type - 不要因为“
type更灵活”就把所有对象都写成type——这会让继承、扩展、编辑器提示变弱 - 也不要因为“
interface更正式”就强行把string | number包进interface——TypeScript 会报错
常见误用与修复建议
以下写法看似省事,实则埋坑:
- ❌
type User = { name: string } & { age: number }→ 复杂交叉不如直接写interface User { name: string; age: number } - ❌ 在
interface里写联合字面量(status: 'loading' | 'done')→ 可以,但推荐抽成type Status = ...再复用 - ❌ 把函数参数类型写成匿名对象字面量(
(user: { name: string }) => void)→ 应该定义interface User或type User,提升可读性和复用性


















