TS 內(nèi)置工具類型中的 keyof 操作符有啥用?
你用過(guò)上圖中 Partial、Required、Record 和 Pick 這些工具類型么?在這些工具類型內(nèi)部都使用了 keyof 操作符,那么該操作符的作用是什么?如果不清楚的話,閱讀完本期的內(nèi)容,也許你就懂了。
在 JavaScript 中,我們可以通過(guò) Object.keys 方法來(lái)獲取對(duì)象中的鍵,返回的是鍵組成的數(shù)組。
const user = {
id: 666,
name: "阿寶哥",
}
const keys = Object.keys(user); // ["id", "name"]
而在 TypeScript 中,我們面對(duì)的是類型。如果要獲取對(duì)象類型中的鍵,就需要使用 keyof 操作符。該操作符是在 TypeScript 2.1 版本中引入的,用于獲取某種類型中的所有鍵,其返回類型是聯(lián)合類型。
type User = {
id: number;
name: string;
}
type UserKeys = keyof User; // "id" | "name"
在獲取對(duì)象類型的鍵之后,我們就可以通過(guò)類似屬性訪問(wèn)的語(yǔ)法來(lái)訪問(wèn)該鍵對(duì)應(yīng)的值的類型。
type U1 = User["id"] // number
type U2 = User["id" | "name"] // string | number
type U3 = User[keyof User] // string | number
那么在實(shí)際工作中,keyof 操作符有什么用呢?這里我們來(lái)舉一個(gè)例子。
這是一個(gè)簡(jiǎn)單的 getProperty 函數(shù),它接收 obj 和 key 兩個(gè)參數(shù),用于獲取 obj 對(duì)象上 key 參數(shù)對(duì)應(yīng)的屬性值。
function getProperty(obj, key) {
return obj[key];
}
const user = {
id: 666,
name: "阿寶哥",
}
const userName = getProperty(user, "name");
那么在 TS 中如何定義上述的 getProperty 函數(shù)呢?這里我們直接把該函數(shù)復(fù)制到 TS 項(xiàng)目中。對(duì)于上述的代碼,TS 編譯器會(huì)提示以下錯(cuò)誤信息:
參數(shù)“obj”隱式具有“any”類型。ts(7006)
參數(shù)“key”隱式具有“any”類型。ts(7006)
該信息告訴我們 obj 和 key 參數(shù)隱式具有 "any" 類型。要解決該問(wèn)題,我們可以顯式定義 obj 和 key 參數(shù)的類型。
function getProperty(obj: object, key: string) {
return obj[key]; // Error
}
設(shè)置之后參數(shù)上的錯(cuò)誤消息消失了,但函數(shù)體中又出現(xiàn)了新的錯(cuò)誤信息:
元素隱式具有 "any" 類型,因?yàn)轭愋蜑?/span> "string" 的表達(dá)式不能用于索引類型 "{}"。
在類型 "{}" 上找不到具有類型為 "string" 的參數(shù)的索引簽名。ts(7053)
那么又該如何解決上述問(wèn)題呢?這時(shí)我們可以使用 TS 泛型和本期的主角 keyof 操作符:
function getProperty<T extends object, K extends keyof T>(
obj: T, key: K
) {
return obj[key];
}
在以上代碼中,我們定義了兩個(gè)類型變量 T 和 K。對(duì)于類型變量 T 使用 extends 約束該類型變量對(duì)應(yīng)的實(shí)際類型必須是 object 類型的子類型。而類型變量 K 也使用 extends 約束該類型變量對(duì)應(yīng)的實(shí)際類型為對(duì)象類型所有鍵組成的聯(lián)合類型的子類型。
之后,利用 getProperty 函數(shù),我們就可以獲取指定屬性的值。當(dāng) key 對(duì)應(yīng)的屬性不存在時(shí),TS 將會(huì)提示相應(yīng)的錯(cuò)誤。
const userId = getProperty(user, "id"); // Ok
const userName = getProperty(user, "name"); // Ok
const userAge = getProperty(user, "age"); // Error
keyof 操作符不僅可以應(yīng)用于對(duì)象類型,也可以應(yīng)用在基本數(shù)據(jù)類型、any 類型、類和枚舉類型上。
type K1 = keyof boolean; // "valueOf"
type K2 = keyof number; // "toString" | "toFixed" | "toExponential" | "toPrecision" | "valueOf" | "toLocaleString"
type K3 = keyof any; // string | number | symbol
class Person {
id: number = 666;
name: string = "阿寶哥";
}
type P = keyof Person; // "id" | "name"
enum HttpMethod {
Get,
Post,
}
type Method = keyof typeof HttpMethod; // "Get" | "Post"
keyof 操作符的另一個(gè)常見用途是映射類型,關(guān)于映射類型的相關(guān)知識(shí)點(diǎn),阿寶哥將在后面的文章中單獨(dú)介紹。
閱讀完本文之后,你應(yīng)該就知道 TS 內(nèi)置工具類型中 keyof 操作符的作用了。