在 TypeScript 中建立類似於 Keyof 的自定義 Valueof 來返回屬性值型別的聯合

David Mbochi Njonge 2023年10月8日
  1. 在 TypeScript 中使用 valueof 返回屬性值型別的聯合
  2. 在 TypeScript 中使用 keyoftypeof 返回屬性值型別的聯合
  3. 使用 TypeScript 中的單個鍵獲取屬性值型別
  4. 在 TypeScript 中使用泛型在編譯時檢查鍵值
在 TypeScript 中建立類似於 Keyof 的自定義 Valueof 來返回屬性值型別的聯合

在本教程中,我們將學習可以用來返回構成屬性或物件的型別的不同方法。

我們可以使用三種方法來實現此功能。其中一種方法利用泛型建立名為 valueof 的自定義型別,該型別返回屬性的所有聯合型別。

第二種方法使用 keyoftypeof 型別返回屬性的所有聯合型別。第三種方法根據需要使用單獨的鍵返回單一型別。

我們還將學習在編譯時限制鍵值條目,如果它們不是同一型別,則通過利用泛型和索引訪問型別。

在 TypeScript 中使用 valueof 返回屬性值型別的聯合

轉到 Visual Studio Code 並建立一個名為 typescript-types 的資料夾或使用你喜歡的任何名稱。在資料夾下建立一個名為 value-types-using-valueof.ts 的檔案。

將以下程式碼複製並貼上到 value-types-using-valueof.ts 檔案中。

type ValueOf<T> = T[keyof T];

type Customer = {
    firstName: string,
    lastName: string,
    doB: Date,
}

type ValueOfCustomer = ValueOf<Customer>

let customer: Customer  ={
    firstName: 'john',
    lastName: 'doe',
    doB: new Date(2022,12,6),
}

function logDetails(customerInfo: ValueOfCustomer){
   console.log(customerInfo)
}

logDetails(customer.firstName)
logDetails(customer.lastName)
logDetails(customer.doB)
logDetails(500)// Error - The union does not include type number

首先,我們定義一個泛型型別 ValueOf<T> 並將其分配給 T[keyof T]T 表示任何型別都可以傳遞給 ValueOf,無論是屬性還是物件。

keyof 返回屬於傳遞型別的所有鍵型別的聯合。

我們建立了包含屬性 firstNamelastNamedoBCustomer 物件。前兩個屬性是字串型別,最後一個屬性是日期型別。

接下來,我們通過將 Customer 傳遞給 ValueOf<Customer> 泛型型別,建立了一個名為 ValueOfCustomer 的型別。ValueOfCustomer 是我們的新型別,由 Customer 物件中所有關鍵時間的聯合組成。

這意味著 ValueOfCustomer 只能接受型別為字串和日期的值。

為了驗證,我們建立了一個名為 logDetails() 的方法,該方法接受 ValueOfCustomer 型別的引數,並使用它記錄 CustomerfirstNamelastNamedoB

請注意,如果我們嘗試在方法中傳遞非字串或日期型別的值,例如數字,我們將收到錯誤,因為方法引數只接受字串或數字。

在 TypeScript 中使用 keyoftypeof 返回屬性值型別的聯合

在同一資料夾中,建立一個名為 value-types-using-keyof-and-typeof.ts 的檔案。將以下程式碼複製並貼上到檔案中。

type Customer = {
    firstName: string,
    lastName: string,
    doB: Date,
}

const customer: Customer  ={
    firstName: 'john',
    lastName: 'doe',
    doB: new Date(2022,12,6),
} as const

type customertypes = typeof customer[keyof Customer]

function getCustomerInfo(theCustomerTypes: customertypes){
    console.log(theCustomerTypes)
}

getCustomerInfo(customer.firstName)
getCustomerInfo(customer.lastName)
getCustomerInfo(customer.doB)
getCustomerInfo(234)//Error - The union does not include type number

在上面的程式碼中,我們定義了包含屬性 firstNamelastNamedoBCustomer 型別。前兩個屬性是字串型別,最後一個屬性是日期型別。

Customer 物件使用物件中每個屬性的具體值進行初始化。名為 customertypes 的型別已建立並分配給 typeof customer[keyof customer]

在最後一個例子中,我們提到 keyof 返回所有鍵型別的聯合。這已經應用到我們的 Customer 物件上來做同樣的事情。

typeof 將返回從 Customer 物件獲取的所有型別,這是在 keyof 的幫助下實現的,如程式碼所示。

為了驗證這一點,我們建立了一個名為 getCustomerInfo() 的方法,該方法接受 customertypes 型別的引數,並使用它來記錄 Customer 物件的值。

請注意,如果我們嘗試傳遞非字串或日期型別的值(例如數字),則在該方法中,我們將收到錯誤訊息,因為新型別不包含型別編號。

使用 TypeScript 中的單個鍵獲取屬性值型別

在上面的兩個示例中,我們已經介紹瞭如何檢索所有值型別的聯合,但在某些情況下,你可能只對一種型別的物件感興趣。

在此示例中,你將學習如何使用單個鍵檢索物件的單個值型別。

在同一資料夾下,建立一個名為 individual-keys.ts 的檔案。將以下程式碼複製並貼上到檔案中。

type Customer = {
    firstName: string,
    lastName: string,
    doB: Date,
}

type date = Customer['doB']

function getDateOfBirth(doB: date): Date{
    return doB;
}

let customer: Customer  ={
    firstName: 'john',
    lastName: 'doe',
    doB: new Date(2022,12,6),
}

getDateOfBirth(customer.doB)
getDateOfBirth(123)//Error - Method accepts a single parameter of type date

在此示例中,我們重用了與前面示例中相同的客戶定義。日期型別是通過使用 Customer['doB'] 引用客戶定義中的 doB 鍵建立的。

這意味著新的 date 型別是 Date 型別。getDateOfBirth() 包含一個 date 型別的引數,並已用於驗證是否只能將日期型別傳遞給它,如程式碼所示。

如果我們嘗試傳遞一個不是 date 型別的值,例如一個數字,我們會得到一個錯誤,因為引數被限制為單一型別。

在 TypeScript 中使用泛型在編譯時檢查鍵值

如前面的示例所示,物件由鍵和值組成。有時我們可能會面臨根據其鍵更改物件值的要求。

在本教程中,我們將學習確保在編譯時檢查我們傳遞的值,以確保它們與鍵的型別相同。

在同一資料夾下建立一個名為 key-value-checking.ts 的檔案。將以下程式碼複製並貼上到檔案中。

type Shipment = {
    containerItems: string,
    containerSerial: string
    shipmentDate: Date
}

declare function updateShipment<K extends keyof Shipment>(key: K, value: Shipment[K]): void;

updateShipment('containerItems','flowers')
updateShipment('containerSerial','def456');
updateShipment('shipmentDate',new Date(2018,3,14))
updateShipment('shipmentDate',1337)// Error- Shipment object does not contain type number

在上面的程式碼中,我們定義了一個名為 Shipment 的物件,其中包含引數 containerItemscontainerSerialshipmentDate

前兩個屬性是字串型別,最後一個屬性是日期型別。我們定義了一個名為 updateShipment() 的通用方法。

updateShipment() 方法接受兩個引數,其中一個是鍵,第二個是 Shipment 物件的值。

鍵必須是任何型別的 Shipment 物件鍵,並使用尖括號引數中的 <K extends keyof Shipment> 進行檢查。

由於我們有鍵 K,我們可以通過使用 Shipment[K] 索引 Shipment 物件的鍵來限制傳遞給該鍵的值。使用此定義,我們為鍵輸入的每個值都必須與鍵的型別相同。

請注意,如果你嘗試傳遞未在 Shipment 物件中定義的值,例如數字,編譯器會標記問題。

David Mbochi Njonge avatar David Mbochi Njonge avatar

David is a back end developer with a major in computer science. He loves to solve problems using technology, learning new things, and making new friends. David is currently a technical writer who enjoys making hard concepts easier for other developers to understand and his work has been published on multiple sites.

LinkedIn GitHub

相關文章 - TypeScript Type