1.keyof
keyof的作用是用来遍历ts中某些类型的属性,例如对象类型,接口类型,类等,例如
interface response {
data: [];
code: number;
location: string
}
type keys = keyof response
// keyof response返回的是一个字符串组成字面量类型,即等价于:
// type keys = 'data' | 'code' | 'location',keys只能是这三个字符串中的其中一个
class Person {
name: string = 'liming'
age: number = 123
}
type classKeys = keyof Person // 'name' | 'age'
let key1: classKeys = 'name'
key1 = 'laoction' // ts报错
所以看见keyof就知道大概是想获取对象、接口、类的属性名组成的字符串别名。
1.1 keyof的作用
我们通常会在函数中的参数中获取对象的属性值
function getValue(obj: object, key: string) {
return obj[key] // 这时候会报ts错误,显示Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'.
}
主要问题是ts不知道我们输入的属性是否在对象中已经存在,所以我们告诉ts,属性名在对象中已经存在。
function getValue<T extends object, key extends keyof T>(obj: T, params: K) {
return obj[params]
}
// 但是这个时候ts还是报错,主要的报错原因在object继承上,
// 报错:Don't use `object` as a type. The `object` type is currently hard to use ([see this issue]
// Consider using `Record<string, unknown>` instead, as it allows you to more easily inspect and use the keys @typescript-eslint/ban-types
// 修正如下:
function getValue<T extends Record<string, unknown>, key extends keyof T> (obj: T, params: key) {
return obj[params]
}
这里是通过使用Record类型(TS内置的高级类型),来替代object对象类型,使用方法为Record<string, unknown>,<>中分别定义key,value的类型,例如<string, number>就表示object的key是string类型,number是value的类型。而一般使用<string, unknown>来表示常规的obejct类型。所以遇到函数中获取属性的,可以如下书写:
function getValue<T extends Record<string, unknown>, K extends keyof T> (obj: T, params: K) {
return obj[params]
}
3.keyof和typeof的区别
在于keyof是获取类型成员的属性名,也就是说keyof不能用于变量,即
interface person {
name: string
}
let obj = {
name: 'liming'
}
keyof obj // 这种是错误的
keyof person // 这种是正确的
// 那么假如我只知道变量,不知道变量的类型,怎么获取属性
// 组合使用 :
type newObj = keyof typeof obj // 这样先将变量转化为类型,再使用keyof即可