在学习 TypeScript 中遇到了Record 这个类型, 一开始不知道其用途, 查找了一下说明才得知:
Record<K extends keyof any, T>
是 TypeScript 提供的一个实用类型(utility type),用于构造一个对象类型,其中键 K
的集合可以是任意类型(通常是字符串、数字或符号),对应的值类型为 T
。
1. 详细解释
1.1 定义
Record<K extends keyof any, T>
的定义如下:
type Record<K extends keyof any, T> = {
[P in K]: T;
};
K extends keyof any
:表示K
可以是任何合法的键类型。keyof any
是 TypeScript 中的一个特殊类型,它等价于string | number | symbol
。T
:表示属性的值的类型。{ [P in K]: T; }
:这是一种映射类型语法,表示生成一个对象类型,这个对象的键是K
中的每一个键,其对应的值类型都是T
。
1.2 用法示例
-
创建一个简单的对象类型:
假设我们想要创建一个对象类型,键是字符串,值是数字:type StringToNumberMap = Record<string, number>; const example: StringToNumberMap = { a: 1, b: 2, c: 3 };
-
限制键的集合:
假设我们有一组特定的键,值的类型是布尔型:type Options = "option1" | "option2" | "option3"; type OptionFlags = Record<Options, boolean>; const example: OptionFlags = { option1: true, option2: false, option3: true };
-
结合接口使用:
如果我们有一个接口Person
,我们想要创建一个包含多个Person
对象的记录:interface Person { name: string; age: number; } type PersonDictionary = Record<string, Person>; const persons: PersonDictionary = { john: { name: "John Doe", age: 25 }, jane: { name: "Jane Smith", age: 30 } };
1.3 详细示例
假设我们需要管理一组用户,每个用户都有一个唯一的标识符(ID)。我们可以使用 Record
来定义一个用户字典:
interface User {
id: number;
name: string;
email: string;
}
type UserDictionary = Record<number, User>;
const users: UserDictionary = {
1: { id: 1, name: "John Doe", email: "john.doe@example.com" },
2: { id: 2, name: "Jane Smith", email: "jane.smith@example.com" },
3: { id: 3, name: "Emily Johnson", email: "emily.johnson@example.com" }
};
// 访问用户信息
console.log(users[1].name); // 输出: John Doe
在这个示例中:
User
接口定义了用户对象的结构。UserDictionary
使用Record<number, User>
创建了一个类型,该类型的键是数字,值是User
类型。users
变量是一个UserDictionary
类型的对象,包含多个用户条目。
2. 类型工具
Record<K extends keyof any, T>
类型在 TypeScript 中非常有用,可以用来定义一个键和值类型的映射。它允许我们动态地创建具有特定键集合和值类型的对象类型,广泛应用于需要键值对数据结构的场景。
在 TypeScript 中还有不少类似的类型工具用于操作和转换类型。以下是它们的具体区别和用途:
-
Partial
- 作用:将类型
T
的所有属性变为可选。 - 用法:
interface Person { name: string; age: number; } type PartialPerson = Partial<Person>; // Equivalent to: { name?: string; age?: number; }
- 作用:将类型
-
Required
- 作用:将类型
T
的所有属性变为必需。 - 用法:
interface Person { name?: string; age?: number; } type RequiredPerson = Required<Person>; // Equivalent to: { name: string; age: number; }
- 作用:将类型
-
Readonly
- 作用:将类型
T
的所有属性变为只读。 - 用法:
interface Person { name: string; age: number; } type ReadonlyPerson = Readonly<Person>; // Equivalent to: { readonly name: string; readonly age: number; }
- 作用:将类型
-
Pick<T, K extends keyof T>
- 作用:从类型
T
中挑选一组属性K
组成新的类型。 - 用法:
interface Person { name: string; age: number; address: string; } type PersonNameAndAge = Pick<Person, 'name' | 'age'>; // Equivalent to: { name: string; age: number; }
- 作用:从类型
-
Record<K extends keyof any, T>
- 作用:构建一个类型,其键为
K
类型,值为T
类型。 - 用法:
type PersonRecord = Record<string, number>; // Equivalent to: { [key: string]: number; }
- 作用:构建一个类型,其键为
-
Exclude<T, U>
- 作用:从类型
T
中排除可以赋值给U
的类型。 - 用法:
type T = string | number | boolean; type Excluded = Exclude<T, boolean>; // Equivalent to: string | number
- 作用:从类型
-
Extract<T, U>
- 作用:从类型
T
中提取可以赋值给U
的类型。 - 用法:
type T = string | number | boolean; type Extracted = Extract<T, boolean>; // Equivalent to: boolean
- 作用:从类型
-
Omit<T, K extends keyof any>
- 作用:构建一个类型,其具有类型
T
的属性,除了那些在K
中的属性。 - 用法:
interface Person { name: string; age: number; address: string; } type PersonWithoutAddress = Omit<Person, 'address'>; // Equivalent to: { name: string; age: number; }
- 作用:构建一个类型,其具有类型
-
NonNullable
- 作用:从类型
T
中排除null
和undefined
。 - 用法:
type T = string | number | null | undefined; type NonNullableT = NonNullable<T>; // Equivalent to: string | number
- 作用:从类型
-
Parameters<T extends (...args: any) => any>
- 作用:获取函数类型
T
的参数类型组成的元组。 - 用法:
type Func = (a: string, b: number) => void; type Params = Parameters<Func>; // Equivalent to: [string, number]
- 作用:获取函数类型
这些类型工具在类型操作和变换中非常有用,帮助开发者更灵活地处理和定义类型。