推荐答案
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 经常与泛型一起使用,以约束函数的参数类型。例如,我们可以编写一个函数,该函数接受一个对象和一个键,并返回该键对应的值。
// www.javascriptcn.com code example
function getProperty<T, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
const user: User = {
id: 1,
name: "Alice",
email: "alice@example.com",
};
const userName = getProperty(user, "name"); // "Alice"
const userEmail = getProperty(user, "email"); // "alice@example.com"在这个例子中,K extends keyof T 表示 K 必须是 T 的键之一。这样,getProperty 函数就可以安全地访问 obj[key],而不会出现类型错误。
3. keyof 与映射类型的结合使用
keyof 还可以与映射类型一起使用,以创建新的类型。例如,我们可以创建一个类型,该类型将对象的所有属性都设置为只读。
// www.javascriptcn.com code example
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
type ReadonlyUser = Readonly<User>;
const readonlyUser: ReadonlyUser = {
id: 1,
name: "Alice",
email: "alice@example.com",
};
// readonlyUser.name = "Bob"; // Error: Cannot assign to 'name' because it is a read-only property.在这个例子中,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 的键之一。