Object.keys
上一个Object.keys()在js中的用法
1 | const obj = { |
试试ts版的
1 | type Person ={ |
Element implicitly has an ‘any’ type because expression of type ‘string’ can’t be used to index type ‘Person’. No index signature with a parameter of type ‘string’ was found on type ‘Person’
来看一下Object.keys的类型声明
1 | interface ObjectConstructor { |
方法接收任意类型的object作为输入并且返回string类型的数组作为输出。
来回到之前的问题,为什么会报错?
在Person中,具体的key值分别是name|age|id,但是它们的索引签名并不是string类型,所以当在keys方法中返回的string数组的每一个key都是string类型时,跟Person中的每个key的索引签名并不匹配,所以是不能通过string类型的key访问到me中的数据,
如果Person这样定义:
1 | interface Person{ |
如果这样写,那么之前的forEach语句就可以正常执行不报错,而且循环中的每个item的类型推导是string类型
注意:那么这个就很有可能是报错的原因。更具体的类型在已经建立索引的库中引发的问题,或者是因为类型过于复杂导致类型不能正确推导
那么遇到这个问题该怎么解决?
最菜的方法就是把tsconfig.json里面的noImplicitAny选项给关了,那回家用JS吧
Type-casting(类型转换)
1 | Object.keys(me).forEach(key=>{ |
这样写法虽然可以,但是不推荐
第二种可以把loop里面的key的类型设置为Person的key,这样就能让ts理解我们在做什么
1 | Object.keys(me).forEach(key=>{ |
这种比之前的要好点,还可以试试其他的,比如让ts自己能够完成这项工作
Extending Object Constructor(继承接口ObjectConstructor)
在ts里面有一个声明合并的特性
1 | interface Person { |
上面的code对Person接口进行了三次的声明,等同于下面这个code
1 | interface Person{ |
所以同理我们可以写ObjectConstructor的接口,写key方法的重载,这次我们需要对object的value值进行细分,并且决定应该返回什么类型
三种行为
- 如果我们传递进来一个number类型,那么应该返回空数组
- 如果我们传递进来一个字符串或者一个数组,那么应该返回string[],也就是字符串数组
- 如果我们传递进来一个any类型,那么直接返回它的key
看一下怎么构造这个类型
1 | type ObjectKeys<T> = T extends object?(keyof T)[]: |
以never结尾来捕捉异常错误
然后写ObjectConstructor
1 | interface ObjectConstructor{ |
把这两段代码放在声明文件中,比如lib.d.ts
然后这个时候执行文章开头的那个loop
1 | Object.keys(me).forEach((key) => { |