淺談TypeScript 索引簽名的理解

我們用兩個對象來描述兩個碼農的工資:

const salary1 = {
  baseSalary: 100_000,
  yearlyBonus: 20_000
};
 
const salary2 = {
  contractSalary: 110_000
};


然後寫一個獲取總工資的函數

function totalSalary(salaryObject: ???) {
  let total = 0;
  for (const name in salaryObject) {
    total += salaryObject[name];
  }
  return total;
}
totalSalary(salary1); // => 120_000
totalSalary(salary2); // => 110_000


如果是你的,要如何聲明totalSalary()函數的salaryObject參數,以接受具有字符串鍵和數字值的對象?

答案是使用一個索引簽名!

接著,我們來看看什麼是 TypeScript 索引簽名以及何時需要它們。

1.什麼是索引簽名

索引簽名的思想是在隻知道鍵和值類型的情況下對結構未知的對象進行類型劃分。

它完全符合salary參數的情況,因為函數應該接受不同結構的salary對象,唯一的要求是屬性值為數字。

我們用索引簽名來聲明salaryObject參數

function totalSalary(salaryObject: { [key: string]: number }) {
  let total = 0;
  for (const name in salaryObject) {
    total += salaryObject[name];
  }
  return total;
}
 
totalSalary(salary1); // => 120_000
totalSalary(salary2); // => 110_000


{[key: string]: number} 是索引簽名,它告訴TypeScript salaryObject 必須是一個以string 類型為鍵,以 number 類型為值的對象。

2. 索引簽名語法

索引簽名的語法相當簡單,看起來與屬性的語法相似,但有一點不同。我們隻需在方括號內寫上鍵的類型,而不是屬性名稱:{ [key: KeyType]: ValueType }。

下面是一些索引簽名的例子。

string 類型是鍵和值。

interface StringByString {
  [key: string]: string;
}
 
const heroesInBooks: StringByString = {
  'Gunslinger': '前端小智',
  'Jack Torrance': '王大志'
};


string 類型是鍵,值可以是 stringnumberboolean

interface Options {
  [key: string]: string | number | boolean;
  timeout: number;
}
 
const options: Options = {
  timeout: 1000,
  timeoutMessage: 'The request timed out!',
  isFileUpload: false
};

簽名的鍵隻能是一個 string`、numbersymbol`。其他類型是不允許的。

3. 索引簽名的註意事項

TypeScript中的索引簽名有一些註意事項,需要註意。

3.1不存在的屬性

如果試圖訪問一個索引簽名為 { [key: string]: string } 的對象的一個不存在的屬性,會發生什麼?

正如預期的那樣,TypeScript 將值的類型推斷為 string。但是檢查運行時值,它是undefined:

根據 TypeScript 提示, value變量是一個 string 類型,但是它的運行時值是 undefined

索引簽名隻是將一個鍵類型映射到一個值類型,僅此而已。如果沒有使這種映射正確,值類型可能會偏離實際的運行時數據類型。

為瞭使輸入更準確,將索引值標記為 string undefined。這樣,TypeScript就會意識到你訪問的屬性可能不存在

3.2 string 和 number 鍵

假設有一個數字名稱的字典:

interface NumbersNames {
  [key: string]: string
}
 
const names: NumbersNames = {
  '1': 'one',
  '2': 'two',
  '3': 'three',
  // ...
};

不會,正常工作。

當在屬性訪問器中作為鍵使用時,JavaScript隱式地將數字強制為字符串(names[1]names['1']相同)。TypeScript也會執行這個強制。

你可以認為 [key: string] 與 [key: string | number] 相同。

4.索引簽名與 Record<Keys, Type>對比

TypeScript有一個實用類型 Record<Keys, Type>,類似於索引簽名。

const object1: Record<string, string> = { prop: 'Value' }; // OK
const object2: { [key: string]: string } = { prop: 'Value' }; // OK

那問題來瞭…什麼時候使用 Record<Keys, Type>,什麼時候使用索引簽名?乍一看,它們看起來很相似

我們知道,索引簽名隻接受 stringnumber symbol 作為鍵類型。如果你試圖在索引簽名中使用,例如,字符串字面類型的聯合作為鍵,這是一個錯誤。

索引簽名在鍵方面是通用的。

但是我們可以使用字符串字面值的聯合來描述 Record<keys, Type>中的鍵

type Salary = Record<'yearlySalary'|'yearlyBonus', number>
 
const salary1: Salary = { 
  'yearlySalary': 120_000,
  'yearlyBonus': 10_000
}; // OK


Record<Keys, Type> 是為瞭具體到鍵的問題。

建議使用索引簽名來註釋通用對象,例如,鍵是字符串類型。但是,當你事先知道鍵的時候,使用Record<Keys, Type>來註釋特定的對象,例如字符串字面量’ prop1' | 'prop2'被用於鍵值。

 總結:

如果你不知道你要處理的對象結構,但你知道可能的鍵和值類型,那麼索引簽名就是你需要的。

索引簽名由方括號中的索引名稱及其類型組成,後面是冒號和值類型: { [indexName: KeyType]: ValueType }, KeyType 可以是一個 stringnumber symbol,而ValueType 可以是任何類型。

到此這篇關於淺談TypeScript 索引簽名的理解的文章就介紹到這瞭,更多相關TypeScript 索引簽名內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: