TypeScript 索引类型
下面是常见的 JavaScript ,实现从对象中选取指定,得到它们的值:
function pluck(o, names) {
return names.map(n => o[n])
}
实现这样的类型定义要满足:
我们可以通过索引类型实现这样的类型定义。
索引类型可以让 TypeScript 编译器覆盖检测到使用了动态名的。
要理解抽象的索引类型,需要先理解索引类型操作符(keyof
)和索引访问操作符(T[K]
)。
keyof
可以对象的可访问索引字符串字面量类型。
interface User {
id: number,
phone: string,
nickname: string,
readonly department: string,
}
class Token{
private secret: string | undefined
public accessExp: number = *
public refreshExp: number = * * * *
}
let user: keyof User // let user: "id" | "phone" | "nickname" | "department"
type token = keyof Token // type token = "accessExp" | "refreshExp"
解释:
倒数第二行,通过 let user: keyof User
得到了等价的 let user: "id" | "phone" | "nickname" | "department"
。
最后一行,通过 type token = keyof Token
得到了等价的 type token = "accessExp" | "refreshExp"
,注意这里没有 secret
。
可以看到对于任何类型 T
, keyof T
的结果为 T
上已知的公共名的联合。
通过 keyof
拿到了名,接下来还要拿到名对应值的类型。
还是以上面的 Token 类为例:
class Token{
public secret: string = 'ixeFoe3x.2doa'
public accessExp: number = *
public refreshExp: number = * * * *
}
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]
。
理解了上面这段话,即可定义下面这个:
function getProperty<T, K extends keyof T>(o: T, name: K): T[K] {
return o[name]; // o[name] is of type T[K]
}
解释: 已知参数 o 的类型为 T,参数 name 的类型 K 满足 K extends keyof T
,那么返回值的类型即为 T[K]
。
掌握了 keyof 和 T[K],下面来完整的书写前言中的 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:
}
let values: unkn[] = pluck(person, ['name', 'age'])
console.log(values)
解释: 参数 names: K[]
这种写法表示数组类型。
本节介绍了高级类型中的索引类型,理解起来可能比较抽象,需要多加练习。