TypeScript 索引類型
下面是一個常見的 JavaScript 函數(shù),實現(xiàn)從一個對象中選取指定屬性,得到它們的屬性值:
function pluck(o, names) {
return names.map(n => o[n])
}
實現(xiàn)這樣一個函數(shù)的類型定義要滿足:
- 數(shù)組參數(shù)
names
中的元素,只能是對象o
身上有的屬性。 - 返回類型取決于參數(shù)
o
身上屬性值的類型。
我們可以通過索引類型實現(xiàn)這樣的類型定義。
1. 慕課解釋
索引類型可以讓 TypeScript 編譯器覆蓋檢測到使用了動態(tài)屬性名的代碼。
要理解抽象的索引類型,需要先理解索引類型查詢操作符(keyof
)和索引訪問操作符(T[K]
)。
2. 索引類型查詢操作符 - keyof
keyof
可以獲取對象的可訪問索引字符串字面量類型。
interface User {
id: number,
phone: string,
nickname: string,
readonly department: string,
}
class Token{
private secret: string | undefined
public accessExp: number = 60 * 60
public refreshExp: number = 60 * 60 * 24 * 30 * 3
}
let user: keyof User // let user: "id" | "phone" | "nickname" | "department"
type token = keyof Token // type token = "accessExp" | "refreshExp"
代碼解釋:
倒數(shù)第二行,通過 let user: keyof User
得到了等價的 let user: "id" | "phone" | "nickname" | "department"
。
最后一行,通過 type token = keyof Token
得到了等價的 type token = "accessExp" | "refreshExp"
,注意這里沒有 secret
。
可以看到對于任何類型 T
, keyof T
的結(jié)果為 T
上已知的公共屬性名的聯(lián)合。
3. 索引訪問操作符 - T[K]
通過 keyof
拿到了屬性名,接下來還要拿到屬性名對應(yīng)屬性值的類型。
還是以上面的 Token 類為例:
class Token{
public secret: string = 'ixeFoe3x.2doa'
public accessExp: number = 60 * 60
public refreshExp: number = 60 * 60 * 24 * 30 * 3
}
type token = keyof Token
type valueType = Token[token] // type valueType = string | number
type secret = Token['secret'] // type secret = string
代碼解釋:
通過 Token['secret']
拿到了屬性 secret 的類型為 string。
那么這時,我們知道了一個對象的類型為泛型 T
,這個對象的屬性類型 K
只需要滿足 K extends keyof T
,即可得到這個屬性值的類型為 T[K]
。
理解了上面這段話,即可定義下面這個函數(shù):
function getProperty<T, K extends keyof T>(o: T, name: K): T[K] {
return o[name]; // o[name] is of type T[K]
}
代碼解釋: 已知參數(shù) o 的類型為 T,參數(shù) name 的類型 K 滿足 K extends keyof T
,那么返回值的類型即為 T[K]
。
4. 函數(shù) pluck() 的類型定義
掌握了 keyof 和 T[K],下面來完整的書寫前言中的函數(shù) pluck() :
function pluck<T, K extends keyof T>(o: T, names: K[]): T[K][] {
return names.map(n => o[n])
}
interface Person {
name: string
position: string
age: number
}
let person: Person = {
name: 'Evan',
position: 'Software Engineer',
age: 27
}
let values: unknown[] = pluck(person, ['name', 'age'])
console.log(values)
代碼解釋: 參數(shù) names: K[]
這種寫法表示數(shù)組類型。
5. 小結(jié)
本節(jié)介紹了高級類型中的索引類型,理解起來可能比較抽象,需要多加練習(xí)。