跳到主要内容

TypeScript - keyof 运算符

在 TypeScript 中,keyof 是一个类型操作符(type operator),它用于获取某个对象类型的所有键名,生成一个联合类型(union type)。

简单来说,keyof 可以帮助你获取一个对象类型的“键名集合”,而这些键会以字符串字面量类型的形式存在。这个特性在泛型编程中非常有用,能让你的代码更加类型安全和灵活。

keyof 的语法

keyof 运算符的语法如下:

type Keys = keyof SomeType;

这里,Keys 就是 SomeType 的所有键组成的联合类型。keyof 关键字后面跟一个类型名,返回一个由指定类型的所有键(属性名)组成的联合类型。这允许你动态地访问和操作对象的键。

示例:基本用法

interface Person {
name: string;
age: number;
}

type PersonKeys = keyof Person;

在这个例子中,PersonKeys 的类型等价于:

type PersonKeys = "name" | "age";

也就是说,keyof Person 会返回 nameage 这两个键的字符串字面量联合类型。

示例:与泛型结合使用

keyof 运算符常常与泛型函数一起使用,比如下面这个例子:

function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}

这个函数可以从对象 obj 中安全地获取某个属性,属性名 key 的类型是 T 的键之一。

使用示例:

let person: Person = { name: "Tom", age: 25 };

let personName = getProperty(person, "name"); // 类型是 string
let personAge = getProperty(person, "age"); // 类型是 number

尝试访问一个不存在的键,比如 "gender",会直接在编译时报错:

Error: Argument of type '"gender"' is not assignable to parameter of type 'keyof Person'

这就是 keyof 带来的类型安全性。

示例:映射对象属性

keyof 关键字在将一个对象的属性映射到另一个对象时也很有用。

interface Fruit {
name: string;
color: string;
}

type FruitMapped = {
[K in keyof Fruit]: string;
};

const fruit: FruitMapped = {
name: 'Apple',
color: 'Red',
};

console.log(fruit);

输出结果:

{ name: 'Apple', color: 'Red' }

示例:条件类型映射

keyof 关键字的另一个强大应用是条件类型映射。这允许我们根据某些条件选择性地映射属性。

interface Product {
name: string;
price: number;
inStock: boolean;
}

type DiscountedProducts<T> = {
[K in keyof T]: T[K] extends number ? T[K] | null : T[K];
};

const product: DiscountedProducts<Product> = {
name: 'Widget',
price: 10,
inStock: true,
};

console.log(product);

输出结果:

{ name: 'Widget', price: 10, inStock: true }

示例:用于约束类型

你还可以利用 keyof 来限制泛型类型的取值范围:

function prop<T, K extends keyof T>(obj: T, key: K) {
return obj[key];
}

这样可以确保传入的 key 参数只能是对象中已有的属性名

注意事项

  • keyof 运算符返回的类型是联合类型(即多个值用 | 连接),你可以使用它进行进一步类型操作。
  • 如果你对 anyunknown 使用 keyof,结果是 string | number | symbol,因为它们可以拥有任意键。
  • 如果你使用的是 type SomeType = string | number 这样的联合类型,那么 keyof SomeType 会返回一个交叉类型的键,这通常不是你想要的结果。要小心这类情况。

小结

keyof 是 TypeScript 提供的一个强大类型工具,它可以提取对象类型的所有键,并返回一个键名的联合类型。你可以结合泛型和 keyof 构建出既灵活又安全的工具函数,避免访问不存在的属性,从而让代码更加健壮。在处理复杂对象或构建通用组件时,掌握 keyof 会极大提升你的类型操控能力。