TypeScript: An index signature parameter must be a

2020-07-09 07:35发布

问题:

I'm attempting to create a function to normalize my arrays and it's expecting an output object that is structured like this:

{
  allIds: [1],
  byId: {
    1: {...}
  }
}

OR

{
  allIds: ['1'],
  byId: {
    '1': {...}
  }
}

I'm trying to create an interface called IOutput to cater for this.

I've tried this:

interface IOutput {
  allIds: string[] | number[]
  byId: {
    [key: number | string]: any
  }
}

But it gives me the following error

An index signature parameter type must be 'string' or 'number'. ts(1023)

It seems to work when I do this:

interface IOutput {
  allIds: string[] | number[]
  byId: {
    [key: number]: any
  }
}

OR

interface IOutput {
  allIds: string[] | number[]
  byId: {
    [key: string]: any
  }
}

But that's not what I'm trying to accomplish. I've also tried this and it gives me the same error:

type StringOrNumber = string | number

interface IOutput {
  allIds: string[] | number[]
  byId: {
    [key: StringOrNumber ]: any
  }
}

How can I accomplish what I'm trying to do?

回答1:

This is a limitation of the current way we can write indexes (this will change soon enough). An index signature parameter can only be number or string (exactly those types, not a union of them, not literal types). You can however have two index signatures, one for number and one for string.

There is another small quick, if you have a string signature, you can actually index by number as well. So this means that if the string index and the number index have the same return type you just need the string index

interface IOutput {
    allIds: string[] | number[]
    byId: {
        [key: string]: any
        // [key: number]: any // Valid but not necessary
    }
}

let o: IOutput = {
    allIds: [1],
    byId: {
        1: {}
    }
}
let o2: IOutput = {
    allIds: ['1'],
    byId: {
        '1': {}
    }
}