推荐答案
keyof
是 TypeScript 中的一个操作符,用于获取对象类型的所有键(属性名)组成的联合类型。它通常与泛型一起使用,以约束对象的键类型。
type Person = { name: string; age: number; location: string; }; type PersonKeys = keyof Person; // "name" | "age" | "location"
在上面的例子中,keyof Person
返回 "name" | "age" | "location"
,这是 Person
类型的所有键组成的联合类型。
本题详细解读
1. keyof
的基本用法
keyof
操作符用于获取对象类型的所有键的联合类型。它可以帮助我们在类型系统中更精确地操作对象的键。
interface User { id: number; name: string; email: string; } type UserKeys = keyof User; // "id" | "name" | "email"
在这个例子中,UserKeys
类型是 "id" | "name" | "email"
,这是 User
接口的所有键组成的联合类型。
2. keyof
与泛型的结合使用
keyof
经常与泛型一起使用,以约束函数的参数类型。例如,我们可以编写一个函数,该函数接受一个对象和一个键,并返回该键对应的值。
-- -------------------- ---- ------- -------- -------------- - ------- ----- ------- -- ---- -- - ------ --------- - ----- ----- ---- - - --- -- ----- -------- ------ -------------------- -- ----- -------- - ----------------- -------- -- ------- ----- --------- - ----------------- --------- -- -------------------
在这个例子中,K extends keyof T
表示 K
必须是 T
的键之一。这样,getProperty
函数就可以安全地访问 obj[key]
,而不会出现类型错误。
3. keyof
与映射类型的结合使用
keyof
还可以与映射类型一起使用,以创建新的类型。例如,我们可以创建一个类型,该类型将对象的所有属性都设置为只读。
-- -------------------- ---- ------- ---- ----------- - - -------- -- -- ----- --- ----- -- ---- ------------ - --------------- ----- ------------- ------------ - - --- -- ----- -------- ------ -------------------- -- -- ----------------- - ------ -- ------ ------ ------ -- ------ ------- -- -- - --------- ---------
在这个例子中,Readonly<T>
类型将 T
的所有属性都设置为只读。keyof T
用于遍历 T
的所有键,并将每个键对应的属性设置为只读。
4. keyof
与索引类型的结合使用
keyof
还可以与索引类型一起使用,以获取对象的键的类型。例如,我们可以编写一个函数,该函数接受一个对象和一个键,并返回该键对应的值的类型。
function getPropertyType<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; } const userId = getPropertyType(user, "id"); // number const userName = getPropertyType(user, "name"); // string
在这个例子中,T[K]
表示 T
类型中键 K
对应的值的类型。keyof T
用于确保 K
是 T
的键之一。
5. keyof
与条件类型的结合使用
keyof
还可以与条件类型一起使用,以创建更复杂的类型。例如,我们可以创建一个类型,该类型将对象的所有可选属性提取出来。
type OptionalKeys<T> = { [K in keyof T]: T extends { [P in K]: T[P] } ? never : K; }[keyof T]; type UserOptionalKeys = OptionalKeys<User>; // never
在这个例子中,OptionalKeys<T>
类型将 T
的所有可选属性提取出来。keyof T
用于遍历 T
的所有键,并检查每个键是否是可选的。
6. keyof
与交叉类型的结合使用
keyof
还可以与交叉类型一起使用,以创建更复杂的类型。例如,我们可以创建一个类型,该类型将两个对象的键合并。
type MergeKeys<T, U> = keyof T | keyof U; type UserAndProfileKeys = MergeKeys<User, { bio: string }>; // "id" | "name" | "email" | "bio"
在这个例子中,MergeKeys<T, U>
类型将 T
和 U
的键合并。keyof T | keyof U
表示 T
和 U
的所有键的联合类型。
7. keyof
与类型推断的结合使用
keyof
还可以与类型推断一起使用,以创建更复杂的类型。例如,我们可以创建一个类型,该类型将对象的键推断为字符串字面量类型。
type InferKey<T> = T extends { [key: string]: infer U } ? string : never; type UserKeyType = InferKey<User>; // string
在这个例子中,InferKey<T>
类型将 T
的键推断为字符串字面量类型。keyof T
用于确保 T
是一个对象类型。
8. keyof
与类型保护的结合使用
keyof
还可以与类型保护一起使用,以创建更复杂的类型。例如,我们可以创建一个类型保护函数,该函数检查一个键是否是对象的键之一。
function isKeyOf<T>(obj: T, key: any): key is keyof T { return key in obj; } if (isKeyOf(user, "name")) { console.log(user.name); // "Alice" }
在这个例子中,isKeyOf
函数检查 key
是否是 obj
的键之一。key is keyof T
表示 key
是 T
的键之一。
9. keyof
与类型别名结合使用
keyof
还可以与类型别名一起使用,以创建更复杂的类型。例如,我们可以创建一个类型别名,该类型别名将对象的键提取出来。
type Keys<T> = keyof T; type UserKeys = Keys<User>; // "id" | "name" | "email"
在这个例子中,Keys<T>
类型别名将 T
的键提取出来。keyof T
用于获取 T
的所有键的联合类型。
10. keyof
与类型参数的结合使用
keyof
还可以与类型参数一起使用,以创建更复杂的类型。例如,我们可以创建一个类型参数,该类型参数将对象的键提取出来。
type ExtractKey<T, K extends keyof T> = K; type UserNameKey = ExtractKey<User, "name">; // "name"
在这个例子中,ExtractKey<T, K>
类型参数将 K
提取出来。K extends keyof T
表示 K
必须是 T
的键之一。