在 TypeScript 中使用 keyof 運算子

Shuvayan Ghosh Dastidar 2023年1月30日
  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