欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

在TypeScript中迭代對(duì)象鍵Object.keys不起作用的原因和解決方案

 更新時(shí)間:2023年10月30日 08:58:47   作者:泯瀧  
在TypeScript中迭代對(duì)象鍵object?keys可能是一場(chǎng)噩夢(mèng),以下是我所知道的所有解決方案,文中有詳細(xì)的代碼示例供大家參考,具有一定的參考價(jià)值,需要的朋友可以參考下

原文鏈接:https://www.totaltypescript.com/iterate-over-object-keys-in-typescript

在TypeScript中迭代對(duì)象鍵object keys可能是一場(chǎng)噩夢(mèng)。以下是我所知道的所有解決方案。

快速解釋 - 省流

使用 Object.keys 迭代不起作用,是因?yàn)?Object.keys 返回一個(gè)字符串?dāng)?shù)組,而不是所有鍵的并集。這是設(shè)計(jì)出來的,不會(huì)改變。

function printUser(user: User) {
  Object.keys(user).forEach((key) => {
    // Doesn't work!
    console.log(user[key]);
    // Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'User'.
    // No index signature with a parameter of type 'string' was found on type 'User'.
  });
}

解決方法:

  • 可以在正確的位置投射到 keyof typeof 使其工作:
const user = {
  name: "Daniel",
  age: 26,
};
 
const keys = Object.keys(user);
 
keys.forEach((key) => {
  console.log(user[key as keyof typeof user]);
});
  • 自定義類型謂詞也可以通過內(nèi)聯(lián)縮小類型來工作。
function isKey<T extends object>(
  x: T,
  k: PropertyKey
): k is keyof T {
  return k in x;
}
 
keys.forEach((key) => {
  if (isKey(user, key)) {
    console.log(user[key]);
  }
});

更長(zhǎng)的解釋

這里有一個(gè)問題:使用Object.keys似乎并不像期望的那樣工作。這是因?yàn)樗鼪]有返回你需要的類型。它不是一個(gè)包含所有鍵的類型,而是將其擴(kuò)展為一個(gè)字符串?dāng)?shù)組。

const user = {
  name: "Daniel",
  age: 26,
};
 
const keys = Object.keys(user); // const keys: string[]

這意味著你不能使用鍵來訪問對(duì)象上的值:

const nameKey = keys[0]; // const nameKey: string


user[nameKey];
// Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ name: string; age: number; }'.
// No index signature with a parameter of type 'string' was found on type '{ name: string; age: number; }'.

TypeScript在這里返回字符串?dāng)?shù)組有一個(gè)很好的原因。TypeScript對(duì)象類型是開放式的。

在很多情況下,TS不能保證 Object.keys 返回的鍵實(shí)際上在對(duì)象上,因此將它們擴(kuò)展為字符串是唯一合理的解決方案。查看此問題以了解更多詳細(xì)信息。

在For循環(huán)中

如果你嘗試做一個(gè)For...在循環(huán)中,你也會(huì)失敗的。這是出于同樣的原因——key被推斷為字符串,就像 Object.keys 一樣。

function printUser(user: User) {
    for (const key in user) {
        console.log(user[key]);
        // Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'User'.
        // No index signature with a parameter of type 'string' was found on type 'User'.
    }
}

但在許多情況下,你實(shí)際上能夠確認(rèn)對(duì)象是什么樣的。所以,你是怎么做的?

解決方案1:轉(zhuǎn)換為 keyof typeof

第一個(gè)選項(xiàng)是使用 keyof typeof 將鍵轉(zhuǎn)換為更特定的類型。在下面的示例中,我們將 Object.keys 的結(jié)果轉(zhuǎn)換為包含這些鍵的數(shù)組。

const user = {
  name: "Daniel",
  age: 26,
};
 
const keys = Object.keys(user) as Array<keyof typeof user>;
 
keys.forEach((key) => { 
    // (parameter) key: "name" | "age"
    // No more error!
  console.log(user[key]);
});

我們也可以在索引到對(duì)象的時(shí)候這樣做。在這里, key 仍然是一個(gè)字符串類型-但在我們索引到user時(shí),我們將其轉(zhuǎn)換為 keyof typeof user 。

const keys = Object.keys(user);
 
keys.forEach((key) => {
  // (parameter) key: string
  console.log(user[key as keyof typeof user]);
});

然而,以任何形式使用 as 通常都是不安全的,這也不例外。

const user = {
  name: "Daniel",
  age: 26,
};
 
const nonExistentKey = "id" as keyof typeof user;
// const nonExistentKey: "name" | "age"
 
// No error!
const value = user[nonExistentKey];

對(duì)于這種情況, as 是一個(gè)相當(dāng)強(qiáng)大的工具-正如你所看到的,它讓我們對(duì)TypeScript撒謊。

解決方案2:類型謂詞 Type Predicates

讓我們來看看一些更聰明,可能更安全的解決方案。類型謂詞怎么樣?通過使用 isKey helper,我們可以在索引到對(duì)象之前檢查鍵是否確實(shí)在對(duì)象上。我們通過在 isKey 的返回類型中使用 is 語法來正確推斷TypeScript。

function isKey<T extends object>(
  x: T,
  k: PropertyKey
): k is keyof T {
  return k in x;
}
 
keys.forEach((key) => {
  if (isKey(user, key)) {
    console.log(user[key]);
  }
});

這個(gè)令人敬畏的解決方案來自Stefan Baumgartner關(guān)于這個(gè)主題的偉大博客文章https://fettblog.eu/typescript-iterating-over-objects/

解決方案3:泛型函數(shù)

讓我們來看看一個(gè)稍微奇怪的解決方案。在泛型函數(shù)中,使用 in 操作符將類型縮小到鍵。我真的不知道為什么這里可以這樣用,而非泛型版本不行。

function printEachKey<T extends object>(obj: T) {
  for (const key in obj) {
    console.log(obj[key]);  // const key: Extract<keyof T, string>
  }
}
 
// Each key gets printed!
printEachKey({
  name: "Daniel",
  age: 26,
});

解決方案4:在函數(shù)中包裝Object.keys

另一種解決方案是將 Object.keys 包裝在一個(gè)返回強(qiáng)制轉(zhuǎn)換類型的函數(shù)中。

const objectKeys = <T extends object>(obj: T) => {
  return Object.keys(obj) as Array<keyof T>;
};
 
const keys = objectKeys({
  name: "Daniel",
  age: 26,
});
 
console.log(keys); // const keys: ("name" | "age")[]

這可能是最容易被濫用的解決方案——將轉(zhuǎn)換操作隱藏在函數(shù)內(nèi)部的方法會(huì)使其更具吸引力,但可能導(dǎo)致人們?cè)谑褂脮r(shí)不加思考。

結(jié)論

我的首選解決方案?通常情況下,類型轉(zhuǎn)換非常完美地完成了工作。它簡(jiǎn)單易懂,并且通常足夠安全。

但是如果你喜歡類型謂詞或通用解決方案的外觀,請(qǐng)盡管使用。isKey函數(shù)看起來很有用,我會(huì)在下一個(gè)項(xiàng)目中借用它。

以上就是在TypeScript中迭代對(duì)象鍵Object.keys不起作用的原因和解決方案的詳細(xì)內(nèi)容,更多關(guān)于TypeScript Object.keys不起作用的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論