淺談TypeScript 索引簽名的理解
我們用兩個(gè)對(duì)象來(lái)描述兩個(gè)碼農(nóng)的工資:
const salary1 = {
baseSalary: 100_000,
yearlyBonus: 20_000
};
const salary2 = {
contractSalary: 110_000
};
然后寫(xiě)一個(gè)獲取總工資的函數(shù)
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()函數(shù)的salaryObject參數(shù),以接受具有字符串鍵和數(shù)字值的對(duì)象?
答案是使用一個(gè)索引簽名!
接著,我們來(lái)看看什么是 TypeScript 索引簽名以及何時(shí)需要它們。
1.什么是索引簽名
索引簽名的思想是在只知道鍵和值類(lèi)型的情況下對(duì)結(jié)構(gòu)未知的對(duì)象進(jìn)行類(lèi)型劃分。
它完全符合salary參數(shù)的情況,因?yàn)楹瘮?shù)應(yīng)該接受不同結(jié)構(gòu)的salary對(duì)象,唯一的要求是屬性值為數(shù)字。
我們用索引簽名來(lái)聲明salaryObject參數(shù)
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 必須是一個(gè)以string 類(lèi)型為鍵,以 number 類(lèi)型為值的對(duì)象。
2. 索引簽名語(yǔ)法
索引簽名的語(yǔ)法相當(dāng)簡(jiǎn)單,看起來(lái)與屬性的語(yǔ)法相似,但有一點(diǎn)不同。我們只需在方括號(hào)內(nèi)寫(xiě)上鍵的類(lèi)型,而不是屬性名稱:{ [key: KeyType]: ValueType }。
下面是一些索引簽名的例子。
string 類(lèi)型是鍵和值。
interface StringByString {
[key: string]: string;
}
const heroesInBooks: StringByString = {
'Gunslinger': '前端小智',
'Jack Torrance': '王大志'
};
string 類(lèi)型是鍵,值可以是 string、number或boolean
interface Options {
[key: string]: string | number | boolean;
timeout: number;
}
const options: Options = {
timeout: 1000,
timeoutMessage: 'The request timed out!',
isFileUpload: false
};
簽名的鍵只能是一個(gè) string`、number或 symbol`。其他類(lèi)型是不允許的。

3. 索引簽名的注意事項(xiàng)
TypeScript中的索引簽名有一些注意事項(xiàng),需要注意。
3.1不存在的屬性
如果試圖訪問(wèn)一個(gè)索引簽名為 { [key: string]: string } 的對(duì)象的一個(gè)不存在的屬性,會(huì)發(fā)生什么?
正如預(yù)期的那樣,TypeScript 將值的類(lèi)型推斷為 string。但是檢查運(yùn)行時(shí)值,它是undefined:

根據(jù) TypeScript 提示, value變量是一個(gè) string 類(lèi)型,但是它的運(yùn)行時(shí)值是 undefined。
索引簽名只是將一個(gè)鍵類(lèi)型映射到一個(gè)值類(lèi)型,僅此而已。如果沒(méi)有使這種映射正確,值類(lèi)型可能會(huì)偏離實(shí)際的運(yùn)行時(shí)數(shù)據(jù)類(lèi)型。
為了使輸入更準(zhǔn)確,將索引值標(biāo)記為 string 或 undefined。這樣,TypeScript就會(huì)意識(shí)到你訪問(wèn)的屬性可能不存在

3.2 string 和 number 鍵
假設(shè)有一個(gè)數(shù)字名稱的字典:
interface NumbersNames {
[key: string]: string
}
const names: NumbersNames = {
'1': 'one',
'2': 'two',
'3': 'three',
// ...
};

不會(huì),正常工作。
當(dāng)在屬性訪問(wèn)器中作為鍵使用時(shí),JavaScript隱式地將數(shù)字強(qiáng)制為字符串(names[1]與names['1']相同)。TypeScript也會(huì)執(zhí)行這個(gè)強(qiáng)制。
你可以認(rèn)為 [key: string] 與 [key: string | number] 相同。
4.索引簽名與 Record<Keys, Type>對(duì)比
TypeScript有一個(gè)實(shí)用類(lèi)型 Record<Keys, Type>,類(lèi)似于索引簽名。
const object1: Record<string, string> = { prop: 'Value' }; // OK
const object2: { [key: string]: string } = { prop: 'Value' }; // OK
那問(wèn)題來(lái)了...什么時(shí)候使用 Record<Keys, Type>,什么時(shí)候使用索引簽名?乍一看,它們看起來(lái)很相似
我們知道,索引簽名只接受 string、number 或 symbol 作為鍵類(lèi)型。如果你試圖在索引簽名中使用,例如,字符串字面類(lèi)型的聯(lián)合作為鍵,這是一個(gè)錯(cuò)誤。

索引簽名在鍵方面是通用的。
但是我們可以使用字符串字面值的聯(lián)合來(lái)描述 Record<keys, Type>中的鍵
type Salary = Record<'yearlySalary'|'yearlyBonus', number>
const salary1: Salary = {
'yearlySalary': 120_000,
'yearlyBonus': 10_000
}; // OK
Record<Keys, Type> 是為了具體到鍵的問(wèn)題。
建議使用索引簽名來(lái)注釋通用對(duì)象,例如,鍵是字符串類(lèi)型。但是,當(dāng)你事先知道鍵的時(shí)候,使用Record<Keys, Type>來(lái)注釋特定的對(duì)象,例如字符串字面量' prop1' | 'prop2'被用于鍵值。
總結(jié):
如果你不知道你要處理的對(duì)象結(jié)構(gòu),但你知道可能的鍵和值類(lèi)型,那么索引簽名就是你需要的。
索引簽名由方括號(hào)中的索引名稱及其類(lèi)型組成,后面是冒號(hào)和值類(lèi)型: { [indexName: KeyType]: ValueType }, KeyType 可以是一個(gè) string、number 或 symbol,而ValueType 可以是任何類(lèi)型。
到此這篇關(guān)于淺談TypeScript 索引簽名的理解的文章就介紹到這了,更多相關(guān)TypeScript 索引簽名內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
漂亮的仿flash菜單,來(lái)自藍(lán)色經(jīng)典
漂亮的仿flash菜單,來(lái)自藍(lán)色經(jīng)典...2006-06-06
lodash內(nèi)部方法getFuncName及setToString剖析詳解
本篇章我們主要是通過(guò)了解lodash里的兩個(gè)內(nèi)部方法getFuncName方法和setToString方法,在實(shí)際開(kāi)發(fā)中我們也可以借鑒方法的實(shí)現(xiàn)思路,在需要的時(shí)候簡(jiǎn)單封裝一下,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09
Intl對(duì)象DateTimeFormat?ListFormat?RelativeTimeFormat使用講解
這篇文章主要為大家介紹了Intl對(duì)象DateTimeFormat?ListFormat?RelativeTimeFormat使用講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
LoadRunner調(diào)用JS加密后登錄實(shí)現(xiàn)
這篇文章主要為大家介紹了LoadRunner調(diào)用JS加密后登錄實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
TypeScript 內(nèi)置高級(jí)類(lèi)型編程示例
這篇文章主要為大家介紹了TypeScript 內(nèi)置高級(jí)類(lèi)型編程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09
前端取消請(qǐng)求及取消重復(fù)請(qǐng)求方式
這篇文章主要為大家介紹了前端取消請(qǐng)求及取消重復(fù)請(qǐng)求方式,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07
async-validator實(shí)現(xiàn)原理源碼解析
這篇文章主要為大家介紹了async-validator實(shí)現(xiàn)原理源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01

