在 TypeScript 中使用 keyof 运算符

Shuvayan Ghosh Dastidar 2023年1月30日 2022年5月18日
  1. 在 TypeScript 中使用 keyof 运算符
  2. 在 TypeScript 中使用带有泛型的 keyof 运算符
  3. 在 TypeScript 中对映射类型使用 keyof 运算符
  4. 在 TypeScript 中使用 keyof 运算符通过 typeof 运算符从枚举中提取键
  5. 在 TypeScript 中使用 keyof 运算符定义 Getter
  6. 结论
在 TypeScript 中使用 keyof 运算符

本教程演示了如何在 TypeScript 中使用 keyof 运算符。

在 TypeScript 中,有两种类型,用户定义和原始类型,如数字、布尔值和字符串。

用户定义类型通常是对象中原始类型的组合。它可以是表示嵌套或简单键值对的对象。

在 TypeScript 中使用 keyof 运算符

我们可以使用 keyof 运算符将类型的公共属性名称提取为联合。它是一个重要的运算符,广泛用于编写泛型和重用现有类型。

例子:

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

type PersonType = keyof Person;

const AgeAttribute : PersonType = 'age'
const NameAttribute : PersonType = 'name';

上面是一个简单的例子,说明了我们如何使用 keyof 运算符从 TypeScript 中的用户定义类型中提取键。

keyof 运算符将类型的所有键作为类型的字符串联合返回。它还可以找到传递给原始类型的键。

type PrimitiveNumberKeys = keyof number;
// "toString" | "toFixed" | "toExponential" | "toPrecision" | "valueOf" | "toLocaleString"

尽管 keyof 运算符对于原始类型可能不方便,但我们仍然可以将其应用于原始类型和用户定义类型。

在 TypeScript 中使用带有泛型的 keyof 运算符

TypeScript 泛型对于制作广泛接受的函数定义和类型至关重要。

keyof 运算符可以为函数泛型的自由度添加一些约束。以下代码段解释了我们如何实现这一点。

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

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

const witcher : Person = {
    name : 'Geralt',
    age : 95
}

console.log(getWitcherAttribute(witcher, 'name'));

输出:

"Geralt"

这个 keyof 运算符可以用作用户定义类型的对象的 getter。

K extends keyof T 将分配给 K 的键限制为 T 类型的键。T[k] 返回与类型 T 相同的类型。

在 TypeScript 中对映射类型使用 keyof 运算符

我们已经看到了 keyof 运算符如何使用 extends 关键字来约束泛型中的某些类型。

我们可以使用 in 关键字进一步将泛型用作映射类型。

以下是 TypeScript 中 Partial 类型的实现。

Partial 类型用于使 TypeScript 中类型的所有字段都是可选的。我们使用 ? 来实现它运算符,使键可选。

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

type Optional<T> = {
    [K in keyof T]? : T[K]
}

const witcher : Optional<Person> = {
    name : "Witcher"
}

同样,我们可以在 TypeScript 中实现 OmitPick 类型。

type PickType<T, K extends keyof T> = {
    [P in K] : T[P]
}

type OmitType<T, K extends keyof T> = PickType<T, Exclude<keyof T, K>>

const witcherWithoutAge : OmitType<Person, 'age'> = {
    name : "Geralt"
};

const witcherWithOnlyAge : PickType<Person, 'age'> = {
    age : 95,
}

这些类型被定义为 PickTypeOmitType 以避免与原始 PickOmit 类型重复。这些是 TypeScript 中使用 keyof 运算符的 PickOmit 的实际实现。

在 TypeScript 中使用 keyof 运算符通过 typeof 运算符从枚举中提取键

keyof 运算符还可以从 enum 中提取键。

例子:

enum Colors {
    Yellow,
    Red,
    Black,
    Blue,
    Green
}

type ColorType = typeof Colors;
type AllColors = keyof ColorType;
// "Yellow" | "Red" | "Black" | "Blue" | "Green"


// it can be also be written together
type AllColors = keyof typeof Colors

该操作符非常方便,可用于进一步创建 Record 类型。

假设创建了一个映射,将 colorType 映射到字符串类型的日志消息。它可以使用 Record 类型来实现。

例子:

type LogColorMap = Record<AllColors, string>

const LogLevel : LogColorMap = {
    Black : "Normal",
    Blue : "Info",
    Green : "Success",
    Red : "Danger",
    Yellow : "Warning"
}

因此,枚举用于使用 keyof 运算符有效地创建另一种类型。

在 TypeScript 中使用 keyof 运算符定义 Getter

我们可以使用 keyof 运算符为类型创建 getter。我们使用映射类型的概念,并使用 Capitalize 类型将键大写。

例子:

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

type Getters<T> = {
    [P in keyof T as `get${Capitalize<string & P>}`] : () => T[P];
}

class PersonCls implements Person, Getters<Person>  {
    age;
    name;
    constructor(){
        this.age = 95;
        this.name = "Geralt";
    }

    getName = () => {
        return this.name;
    }

    getAge = () => {
        return this.age;
    }
}

const witcher = new PersonCls();
console.log(witcher.getName())

输出:

"Geralt"

结论

因此,keyof 运算符有各种用例,特别是在创建具有许多泛型类型的库时使用。此外,它还用于从现有类型中提取类型并创建新类型。

Shuvayan Ghosh Dastidar avatar Shuvayan Ghosh Dastidar avatar

Shuvayan is a professional software developer with an avid interest in all kinds of technology and programming languages. He loves all kinds of problem solving and writing about his experiences.

LinkedIn Website

相关文章 - TypeScript Operator