类型别名(type)
本教程共 80 篇 · 第 27 篇 · 更新于 2026-08-10 · 约 9 分钟阅读
本节目标:学会用 type 关键字给任何类型起别名,了解 type 能做什么、interface 不能做什么,为下一章的选型指南打好基础。
interface 很强大,但它只能描述对象的形状。如果我想给”字符串或数字”这种联合类型起个名字,或者给一个复杂的函数签名起个简短的名字,interface 就力不从心了。
这时候就要请出 type 关键字——类型别名。
type 的基本语法
type Point = {
x: number;
y: number;
};
const p: Point = { x: 10, y: 20 };
乍一看跟 interface 一模一样。事实上,对于纯对象形状,type 和 interface 很多时候可以互换。但 type 的能力远不止于此。
Note叫”别名”是因为它不给类型系统添加新的类型名称——它只是给现有类型起个新名字。比如
type Age = number之后,Age和number在类型检查眼里是完全一样的。
type 能定义什么
interface 只能描述对象形状(含函数签名)。type 几乎什么都能定义:
联合类型
type Status = "pending" | "success" | "error";
type ID = string | number;
function handleStatus(s: Status) {
if (s === "success") {
console.log("操作成功");
}
}
联合类型是 type 的杀手级用例——interface 完全做不了这个。
元组
type Point3D = [number, number, number];
type NameAndAge = [string, number];
const origin: Point3D = [0, 0, 0];
const person: NameAndAge = ["Alice", 25];
同样,元组只能用 type 定义。
函数类型
type Callback = (result: string) => void;
type MathOp = (a: number, b: number) => number;
const add: MathOp = (a, b) => a + b;
const log: Callback = (msg) => console.log(msg);
虽然 interface 也能描述函数(用调用签名),但 type 的写法更简洁直观。
交叉类型
type Named = { name: string };
type Aged = { age: number };
type Person = Named & Aged;
// Person = { name: string; age: number }
交叉类型 & 把多个类型合并。type 做交叉可以任意组合——interface 只能通过 extends 继承。
基本类型的别名
type Name = string;
type Score = number;
type Flag = boolean;
给基本类型起别名,在需要做语义区分的时候很有用。不过要注意这只是”别名”而非”新类型”——Name 和 string 可以互相赋值。
type 的递归自引用
type 可以在自己的定义里引用自己——这对于树形结构、链表等递归数据结构非常实用:
type TreeNode = {
value: number;
left: TreeNode | null;
right: TreeNode | null;
};
const tree: TreeNode = {
value: 1,
left: {
value: 2,
left: null,
right: null,
},
right: {
value: 3,
left: null,
right: null,
},
};
interface 也能做到类似的递归引用,但 type 的写法在某些复杂场景下更灵活——比如和联合类型、泛型搭配时。
type 不能做什么
说了这么多 type 的优势,也得诚实地说它的局限。
type 不支持声明合并
type User = { name: string };
// type User = { age: number }; // ❌ 报错:标识符 "User" 重复
同一个 type 名字不能定义两次。interface 却可以在不同地方多次声明同一个名字,TypeScript 会自动把它们合并。这个区别在第 29 章会详细讲。
type 不能被类 implements 时检测冲突
虽然类可以实现 type 定义的类型:
type HasName = { name: string };
class Person implements HasName {
name = "Alice";
}
但 interface 在 implements 时的错误信息更友好,extends 时的属性冲突检测也更早暴露问题(第 25 章讲过这个区别)。
type vs interface 速查表
| 能力 | interface | type |
|---|---|---|
| 描述对象形状 | ✅ | ✅ |
| 描述函数类型 | ✅(调用签名) | ✅ |
| 描述联合类型 | ❌ | ✅ |
| 描述元组 | ❌ | ✅ |
| 描述原始类型的别名 | ❌ | ✅ |
| 交叉类型 | ❌(需 extends) | ✅(用 &) |
| 声明合并 | ✅ | ❌ |
| extends 继承 | ✅ | ❌(可用 & 替代) |
| 映射类型 | ❌ | ✅ |
| 条件类型 | ❌ | ✅ |
| 被类 implements | ✅ | ✅ |
| 递归自引用 | ✅ | ✅ |
这张表不是要你说”哪个更好”——而是让你知道什么时候该用哪个。具体怎么选,下一章专门聊。
小结
type是类型别名,功能远超 interface——能定义联合、元组、函数、交叉类型等。- type 支持递归自引用,适合描述树、链表等结构。
- type 不支持声明合并,同名 type 重复定义直接报错。
- 大多数简单场景 type 和 interface 可以互换,复杂场景各有擅场。
下一章是这一部分的”重头戏”——我们会把 interface 和 type 放在一起做一次全面的对比,给出在 TypeScript 7.0 语境下的选型建议。