文章
关于TypeScript中的type、interface 和 Record
目录
在 TypeScript 中,type、interface 和 Record 都可用于定义对象类型,但它们在设计目的、功能和使用场景上有显著区别:#
1. interface#
核心特点:
- 专为对象形状(Object Shape) 设计
- 支持声明合并(同名接口自动合并)
- 支持继承(
extends关键字) - 与类(
class)实现天然协作(implements) 使用场景:
interface User {
id: number;
name: string;
}
// 声明合并(扩展属性)
interface User {
email: string;
}
// 继承
interface Admin extends User {
role: "admin";
}
// 类实现
class UserAccount implements User {
id = 1;
name = "Alice";
email = "alice@example.com";
}
适用场景:
- 定义应用核心对象结构(如 API 响应、状态管理)
- 需要扩展或合并定义的场景
- 类实例的类型约束
2. type****(类型别名)#
核心特点:
- 可定义任意类型(对象、联合、元组、原始类型等)
- 支持复杂类型操作(联合
|、交叉&、条件类型等) - 不支持声明合并
- 不可被类
implements(需使用对象形式) 使用场景:
// 对象类型
type Point = { x: number; y: number };
// 联合类型
type ID = string | number;
// 元组类型
type Data = [string, number];
// 交叉类型(组合多个类型)
type AdminUser = User & { permissions: string[] };
适用场景:
- 组合复杂类型(联合、交叉)
- 定义工具类型、泛型操作
- 需要直接引用原始类型(如
type ID = number)
3. Record<Keys, Type>#
核心特点:
- TypeScript 内置的工具类型
- 专门定义键值映射对象
- 语法:
Record<K, T>={ [key in K]: T }使用场景:
// 键为string,值为number
type Scores = Record<string, number>;
// 等价于 { [key: string]: number }
// 使用字面量联合类型约束键
type Weekday = "Mon" | "Tue" | "Wed";
type Schedule = Record<Weekday, string>;
/* 等价于:
{
Mon: string;
Tue: string;
Wed: string;
} */
适用场景:
- 动态键的对象(如字典、映射表)
- 约束键名的枚举对象
- 避免手动写索引签名
关键区别总结#
| 特性 | interface | type | Record<K, T> |
|---|---|---|---|
| 本质 | 对象结构声明 | 任意类型的别名 | 内置工具类型 |
| 扩展 | 支持继承 (extends) | 支持交叉类型 (&) | 需组合其他类型 |
| 声明合并 | ✅ 支持 | ❌ 不支持 | ❌ 不支持 |
| 类实现 | ✅ implements | ❌(除非是对象类型) | ❌ |
| 适用类型 | 对象/函数 | 任意类型(联合、元组等) | 键值映射对象 |
| 动态键 | 需手动添加索引签名 | 需手动添加索引签名 | ✅ 原生支持 |
| 典型用途 | 核心业务对象模型 | 类型组合、工具类型 | 字典/枚举映射结构 |
何时使用?#
interface: 定义应用中的核心数据结构(如User、Product),尤其需要扩展或类实现时。type:- 组合类型(
A & B、X | Y) - 定义元组、函数类型等非对象类型
- 创建工具类型(如
Partial<T>)
- 组合类型(
Record<K, T>:- 键名未知的字典(如
Record<string, boolean>) - 键名受限的映射表(如
Record<"status" | "code", number>) - 替代手动索引签名(更简洁)
- 键名未知的字典(如
示例对比#
// 等效的对象定义方式:
interface UserMap {
[id: string]: User;
}
type UserMapType = {
[id: string]: User;
};
type UserMapRecord = Record<string, User>; // ✅ 最简洁
黄金法则: - 优先用
interface定义对象(除非需要高级类型操作) - 用type处理联合、交叉或工具类型 - 用Record处理键值映射结构