type 与 interface 的区别与共同点
共同点:
- 类型定义:两者都可以用来定义对象类型
// 使用 interface
interface PersonInterface {
name: string;
age: number;
}
// 使用 type
type PersonType = {
name: string;
age: number;
};
- 函数类型定义:两者都可以定义函数类型
// 使用 interface
interface SearchFunc {
(source: string, subString: string): boolean;
}
// 使用 type
type SearchFunc = (source: string, subString: string) => boolean;
- 扩展能力:两者都可以被扩展(但语法不同)
// interface 扩展 interface
interface EmployeeInterface extends PersonInterface {
employeeId: string;
}
// type 扩展 type
type EmployeeType = PersonType & {
employeeId: string;
};
// interface 扩展 type
interface EmployeeInterface2 extends PersonType {
department: string;
}
// type 扩展 interface
type EmployeeType2 = PersonInterface & {
position: string;
};
主要区别:
| 特性 | interface | type | |
|---|---|---|---|
| 声明合并 | ✅ 支持同名接口自动合并 | ❌ 不允许重复声明 | |
| 扩展语法 | extends 关键字 | & 交叉类型 | |
| 描述范围 | 对象/函数类型 | 任意类型(联合、元组、基本类型等) | |
| 实现类 | class X implements Y | 仅支持对象类型 | |
| 元组类型 | ❌ 不支持 | ✅ 支持 type Coord = [number, number] | |
| 联合类型 | ❌ 不支持 | ✅ 支持 `type ID = string | number` |
| 映射类型 | ❌ 不支持 | ✅ 支持 type Readonly<T> = { readonly [P in keyof T]: T[P] } | |
| 错误提示 | 显示接口名称 | 展开具体类型 |
声明合并示例:
interface User {
name: string;
}
interface User {
age: number;
}
// 合并为 { name: string; age: number; }
const user: User = {
name: "Alice",
age: 30
};
最佳实践:
- 使用 interface 定义对象类型和类契约
- 使用 type 定义联合类型、元组或复杂类型操作
- 在公共 API 定义时优先使用 interface(更清晰的错误提示)
交叉类型 (Intersection Types)
交叉类型是将多个类型合并为一个类型,用 & 运算符表示
type Employee = {
id: number;
name: string;
};
type Manager = {
department: string;
manage(): void;
};
// 交叉类型
type ManagerEmployee = Employee & Manager;
const boss: ManagerEmployee = {
id: 1,
name: "Alice",
department: "Engineering",
manage() {
console.log("Managing team");
}
};
关键特点:
- 类型组合:合并多个类型的属性
- 冲突处理:同名属性会合并为交集类型
type A = { value: number; common: string };
type B = { value: string; common: number };
type C = A & B;
// value 成为 never 类型 (number & string)
// common 成为 never 类型 (string & number)
-
与接口继承区别:
- 接口继承:
extends是子集关系 - 交叉类型:
&是集合的交集操作
- 接口继承:
联合类型 (Union Types)
联合类型表示一个值可以是几种类型之一,用 | 运算符表示
type ID = string | number;
type Status = "active" | "inactive" | "pending";
类型守卫 (Type Guards):
处理联合类型时需要缩小类型范围
function printID(id: ID) {
if (typeof id === "string") {
// 此处 id 被识别为 string
console.log(id.toUpperCase());
} else {
// 此处 id 被识别为 number
console.log(id.toFixed(2));
}
}
可辨识联合 (Discriminated Unions):
使用共同字段区分联合类型
type Circle = {
kind: "circle";
radius: number;
};
type Square = {
kind: "square";
sideLength: number;
};
type Shape = Circle | Square;
function getArea(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2;
case "square":
return shape.sideLength ** 2;
}
}
联合类型 vs 交叉类型:
联合类型 vs 交叉类型:
含义: 类型A **或** 类型B | 类型A **且** 类型B
使用场景: 值可能是多种类型之一 | 值必须同时满足多个类型
示例:`string | number` | `Employee & Manager`
类型收缩:需要类型守卫确定具体类型 | 直接包含所有类型的属性
空值处理: 常与 `null` 或 `undefined` 使用 | 不兼容包含 `null` 的类型
// 联合类型示例:可能是字符串或数字数组
type StringOrNumberArray = string[] | number[];
// 交叉类型示例:同时拥有两种类型的所有属性
type Named = { name: string };
type Aged = { age: number };
type Person = Named & Aged;
总结图
TypeScript 类型系统
├── 类型定义
│ ├── interface → 对象类型(支持声明合并)
│ └── type → 任意类型(支持高级类型操作)
│
├── 类型组合
│ ├── 联合类型 (A | B) → "或"关系
│ │ └── 需类型守卫缩小范围
│ │
│ └── 交叉类型 (A & B) → "与"关系
│ └── 合并多个类型属性
│
└── 类型操作
├── keyof → 获取对象键的联合类型
├── typeof → 获取值的类型
└── 条件类型 → T extends U ? X : Y
理解这些核心概念对于掌握 TypeScript 至关重要,特别是在大型项目中保持类型安全和代码可维护性。