Record 是 TypeScript 提供的一个工具类型(Utility Type),它用来快速构造一个对象类型,其中的 键和值的类型都可以指定。
定义#
Record<Keys, Type>Keys: 一组属性键,可以是联合类型(string、number、symbol,或者它们的联合)。
Type: 每个键对应的属性值的类型。
作用#
相当于生成:
{
[K in Keys]: Type
}示例#
基本用法#
type UserRole = "admin" | "user" | "guest";
// 构造一个类型,key 是 UserRole,值是 string
type RoleDescriptions = Record<UserRole, string>;
const roleDesc: RoleDescriptions = {
admin: "Has full access",
user: "Regular user",
guest: "Read-only access"
};这里 roleDesc 必须包含 "admin" | "user" | "guest" 三个键,而且值必须是 string。
限制键的范围#
type Status = "success" | "error" | "loading";
const statusColors: Record<Status, string> = {
success: "green",
error: "red",
loading: "gray"
};如果少写一个键,或者写错,会编译报错。
用于对象映射#
interface User {
id: number;
name: string;
}
type UserMap = Record<number, User>;
const users: UserMap = {
1: { id: 1, name: "Alice" },
2: { id: 2, name: "Bob" }
};这里相当于一个 id -> User 的映射。
对比#
Record<Keys, Type>等价于:{ [K in Keys]: Type }Partial<Record<Keys, Type>>可以让这些键变为可选。
Record vs Map vs 索引签名#
| 特性 | Record<Keys, Type> | Map<Key, Value> | 索引签名 { [key: string]: Type } |
|---|---|---|---|
| 定义位置 | 类型层面:构造对象类型 | 运行时数据结构:ES6 Map | 类型层面:对象的属性约束 |
| 键的范围 | 必须是 已知联合类型 或基本类型 (`string | number | symbol`) |
| 值的类型 | 必须统一为 Type | 任意值 | 必须统一为 Type |
| 是否强制所有键都出现 | 是的(除非用 Partial<Record<...>>) | 否,可以动态增删 | 否,对象可选地添加键 |
| 运行时表现 | 只是个 静态类型约束,编译后消失 | 真实的数据结构,方法丰富(.set(), .get(), .has()) | 普通对象(JS 对象) |
| 适用场景 | 静态定义键值映射(例如 status -> color,role -> permission) | 动态键值存储,需要高效查找、非字符串键 | 需要灵活的对象键,键集合不固定 |
举例对比#
Record#
type Status = "success" | "error" | "loading";
const statusColors: Record<Status, string> = {
success: "green",
error: "red",
loading: "gray"
};
// ✅ 编译时就能发现漏写/拼写错误
Map#
const userMap = new Map<number, string>();
userMap.set(1, "Alice");
userMap.set(2, "Bob");
// ✅ 键可以是对象
const objKey = {};
userMap.set(objKey, "value");索引签名#
const dict: { [key: string]: number } = {};
dict["a"] = 1;
dict["b"] = 2;
// ✅ 键集合完全自由,不做限制
👉 总结一下:
你知道键的全集 → 用
Record(最安全,编译期就能发现错误)。需要运行时动态键值对(特别是对象做 key)→ 用
Map。只想随便存键值,不在意遗漏/拼写错误 → 用 索引签名。