什么是索引签名?三分钟让你搞明白索引签名中的两道老大难问题!!!

70 阅读3分钟

前言

  • 上篇文章讲泛型时提到了索引签名,既然有人问了,那就专门把这一块拎出来单独讲讲
    • 有关于索引签名网上资料很多都没讲明白,比如:
      • 在number和string类型的索引都存在时,为什么number类型的值类型一定得是string类型的值类型的子类型
      • 为什么当一个工具函数接收的参数类型是通过索引签名创建出来的时候,这个索引签名中string类型的key的值类型有时候可以不是any,有时候却必须是any?
      • 那么今天就来一个一个的把这些疑点都解决一下!!!

索引签名

  • 索引签名的概念就是:

    • 有时候,我们在声明一个对象的类型时,并不知道这个对象中以后会有哪些属性,但是我们知道这些属性和属性值有什么特征的时候,就可以使用索引签名来描述这个对象类型中的属性

    • 他的写法就是[索引名称: 索引类型]: 返回值类型

    • 例如:[key: string]: string意思就是可以通过string类型的索引,获取到string类型的值

      • 当别人的工具函数给我们返回的值类型是一个索引签名的时候,我们就可以通过索引签名提示的方式获取到里面具体的值了
      • 此时我们通过info[key]拿到的值的类型是明确的,它就是一个string类型
      interface IInfo {
        [key: string]: string;
      }
      ​
      function getInfo(): IInfo {
        return {};
      }
      ​
      const info = getInfo();
      ​
      for (let key in info) {
        console.log(info[key])
      }  
      
    • 我们在定义一些工具函数的时候,也可以通过索引签名的方式,来要求别人给我们传入特定的值,从而我们可以在工具函数中对这个值做一些操作,例如:

      interface ICollection {
          [index: number]: string,
          length: number
      }
      ​
      // 必须得传入一个对象类型,这个对象,我可以通过number类型的索引,明确的获取到string类型的值,那么拿到string类型值之后就可以对其做一些操作了
      function logCollectionItem(collection: ICollection) {
          for (let i = 0; i < collection.length; i++) {
              console.log(collection[i].length)
          }
      }
      ​
      logCollectionItem(['aaa', 'bbb', 'ccc'])
      
    • 索引名称意思就是:我们自己起的,起一个提示作用,要通过这个集合的什么来取它里面的值,比如:index/key

    • 索引类型的意思就是:我们通过什么类型的值去取它里面的值

      • 索引类型只能有两种类型:number和string,并且不能写写成联合类型,联合类型可就不是string或者number了

      • 并且!!!number类型的索引最终都会被转成string类型的索引

      • 比如数组的话就是通过下标获取值,所以索引类型就是number类型

      • 如果是对象的话,就通过key去取里面的值,所以索引类型就是string类型

      • 并且它支持写两个索引类型

        • 但是需要注意的是:number类型的索引最终也会被转成string类型索引,比如arr[0],其实最终会被转成arr['0']

        • 所以这也就意味着,number类型的索引的返回值,必须是string类型的索引的返回值的子类型,否则就会报错

      • 而且在这里,[key: string]: any中的any并不能被替换成string,这是为什么呢?明明我arr中只有string类型的元素啊

        • 这是因为,我们是通过string类型索引去访问arr的,那么arr身为一个数组,有许多高阶函数,这些高阶函数的名字也是string类型
        • 那就意味着我们可以通过string类型的所以去访问它们
        • 可是如果我们把它返回值的类型写成string了,人家明明获取到的是一个函数类型的值,那就肯定会报错啊!!!这就是原因所在
        interface ICollection {
            [index: number]: string
            [key: string]: any
        }
        ​
        const arr: ICollection = ['aaa', 'bbb', 'ccc']