Barry Michael Doyle
Barry Michael Doyle

Reputation: 10618

TypeScript: An index signature parameter must be a 'string' or 'number' when trying to use string | number

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?

Upvotes: 21

Views: 41713

Answers (2)

Manoj
Manoj

Reputation: 2216

Now the limitation to write indexes has been removed. An index signature parameter can be union of number and string.

type StringMap = { [key: string | number]: unknown };

function createStringPair(property: keyof StringMap, value: number): StringMap {
  return { [property]: value };
}
console.log(createStringPair(5, 10));
console.log(createStringPair("sum", 10));


[LOG]: {
  "5": 10
} 
[LOG]: {
  "sum": 10
} 

Cheers, hope it helps.

Upvotes: 4

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249706

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': {}
    }
}

Upvotes: 21

Related Questions