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
。只想随便存键值,不在意遗漏/拼写错误 → 用 索引签名。