TypeScript `keyof` 操作符详解 – wiki词典

TypeScript keyof 操作符详解

在 TypeScript 的类型系统中,keyof 操作符是一个强大且常用的工具,它允许我们从对象类型中提取其所有公共属性键的联合类型。理解并熟练运用 keyof 对于编写更安全、更灵活且类型推断能力强的 TypeScript 代码至关重要。

keyof 的基本概念

keyof 操作符接收一个对象类型作为参数,并返回一个字符串字面量或数字字面量联合类型,这个联合类型包含了该对象类型所有公共属性的键。

示例 1:基本用法

“`typescript
interface User {
id: number;
name: string;
email: string;
}

type UserKeys = keyof User;
// UserKeys 的类型是 “id” | “name” | “email”
“`

在这个例子中,keyof User 返回了 'id' | 'name' | 'email',这是一个包含 User 接口所有属性名的联合类型。

keyof 与索引签名

当对象类型包含索引签名时,keyof 的行为会略有不同。

示例 2:带有字符串索引签名

“`typescript
interface Dictionary {

length: number; // 明确定义的属性
}

type DictionaryKeys = keyof Dictionary;
// DictionaryKeys 的类型是 string | “length”
“`

这里,keyof Dictionary 返回 string | "length"。这是因为索引签名 [key: string]: any 意味着任何字符串都可以作为 Dictionary 的键,因此 keyof 会将其包含在结果中。

示例 3:带有数字索引签名

“`typescript
interface NumberIndexedArray {

// name: string; // 如果添加字符串属性,结果会是 number | “name”
}

type NumberIndexedArrayKeys = keyof NumberIndexedArray;
// NumberIndexedArrayKeys 的类型是 number
“`

如果对象类型只包含数字索引签名,keyof 会返回 number 类型。

keyof 与泛型

keyof 在泛型编程中发挥着尤其重要的作用,它允许我们创建可以安全地访问对象属性的函数或类。

示例 4:获取对象属性的泛型函数

“`typescript
function getProperty(obj: T, key: K): T[K] {
return obj[key];
}

const user = {
id: 1,
name: ‘Alice’,
age: 30
};

const userName = getProperty(user, ‘name’); // userName 的类型是 string
const userId = getProperty(user, ‘id’); // userId 的类型是 number

// const invalid = getProperty(user, ‘address’);
// 类型错误:Argument of type ‘”address”‘ is not assignable to parameter of type ‘”id” | “name” | “age”‘.
“`

在这个例子中:
T 是我们传入的对象的类型(例如 typeof user)。
K extends keyof T 确保了 key 参数必须是 T 类型的一个属性键。这提供了编译时的类型安全。
T[K] 是一个索引访问类型,它表示 T 类型中由 K 键指向的属性的类型。例如,当 K'name' 时,T[K] 就是 string

这样,getProperty 函数就能够安全地获取任何对象的属性,并且在编译时就能检查出非法的属性访问。

keyoftypeof

keyof 经常与 typeof 结合使用,尤其是在处理 JavaScript 对象字面量时,以便从变量推断出类型并进一步提取其键。

示例 5:结合 typeof 使用

“`typescript
const person = {
firstName: ‘John’,
lastName: ‘Doe’,
age: 40
};

type PersonKeys = keyof typeof person;
// PersonKeys 的类型是 “firstName” | “lastName” | “age”

function printPersonInfo(key: PersonKeys) {
console.log(${key}: ${person[key]});
}

printPersonInfo(‘firstName’); // 输出 “firstName: John”
printPersonInfo(‘age’); // 输出 “age: 40”
“`

这里,typeof person 首先推断出 person 变量的类型,然后 keyof 操作符再从这个推断出的类型中提取键的联合类型。

keyof 的使用场景

  1. 类型安全的对象属性访问: 如泛型函数 getProperty 所示,确保只能访问对象上存在的属性。
  2. 动态属性访问的类型检查: 当你需要在运行时根据字符串变量访问对象属性时,keyof 可以提供编译时保护。
  3. 构建工具函数或库: 许多实用工具函数,如 pickomitmerge 等,都会利用 keyof 来确保参数的类型正确性。
  4. 映射类型: keyof 是映射类型(Mapped Types)的基础,它允许你基于现有类型的键来创建新类型。
    “`typescript
    type Readonly = {
    readonly [P in keyof T]: T[P];
    };

    interface Point {
    x: number;
    y: number;
    }

    type ImmutablePoint = Readonly;
    // ImmutablePoint 的类型是 { readonly x: number; readonly y: number; }
    ``
    在这个
    Readonly映射类型中,P in keyof T迭代了T的所有键,并为每个键创建了一个只读属性。
    5. **联合类型中的类型守卫:** 可以用
    keyof` 来帮助缩小联合类型中的成员。

总结

keyof 操作符是 TypeScript 类型系统中一个极其有用的特性,它通过提供对象属性键的联合类型,极大地增强了类型安全性和代码的表达力。无论是进行类型安全的属性访问、编写泛型函数,还是构建复杂的映射类型,keyof 都是一个不可或缺的工具,它帮助开发者编写出更健壮、更易于维护的 TypeScript 代码。掌握 keyof 的用法,将使你能够更好地利用 TypeScript 的强大功能。

滚动至顶部