Dynamic object keys in TypeScript

I have a problem when setting the type of a dynamic object in TypeScript because the object that i create has dynamic keys and three that are not.

Here’s how i defined the type for the object:

interface GraphReturns {
  [key: string]: {
    '%': number,
     value: number,
     '%Acumulated': number
   },
   total: number,
  'total_%': number,
   date: string
}

The errors i get:

  1. Property ‘total’ of type ‘number’ is not assignable to ‘string’ index type ‘{ ‘%’: number; value: number; ‘%Acumulated’: number; }’
  2. Property ‘‘total_%’’ of type ‘number’ is not assignable to ‘string’ index type ‘{ ‘%’: number; value: number; ‘%Acumulated’: number; }’
  3. Property ‘date’ of type ‘string’ is not assignable to ‘string’ index type ‘{ ‘%’: number; value: number; ‘%Acumulated’: number; }’

How can i fix this? Thank you!

All typescript knows is that your GraphReturns interface has keys that will be strings, and the value is:

{
'%': number,
value: number,
'%Acumulated': number
}

So it’s expecting something like:

let x: GraphReturns = {
  "foo": {...}
  "bar": {...}
}

But then in the next line you also tell TS that the same interface also contains

total: number,
'total_%': number,
date: string

Which now TS cannot verify, because if you tell it that GraphReturns contains all possible keys, do these keys have to be of your object type, or the other type?

Or in other words how can TS know if this is valid or not:

let x: GraphReturns = {
  total: {...}
}

Is total valid or not?


I’m not particularly fond of this solution, and my first advice is to really think and clean up your type to reflect better your app needs.
However you could declare your GraphReturns as an interface that has value that are either one of those object, or the other values.

interface GraphReturns {
[key: string]: ElseValues | WhateverThisIs,
}


interface WhateverThisIs {
'%': number,
value: number,
'%Acumulated': number
}

interface WhateverThisElseIs {
total: number,
'total_%': number,
date: string
}

type ElseValues = WhateverThisElseIs[keyof WhateverThisElseIs]

let x: GraphReturns = {
  total: 12,
  date: {
    '%': 100,
    value: 200,
    '%Acumulated': 20
  },
  somethingRandom: "2022-06-09"
}
2 Likes

Thank you for taking your time to think about a solution!
To be honest, I found it a little complex so I followed your advice and rethought how to structure better the data, and that brought me a really simple solution.

I moved from the question type to this:

interface GraphReturns {
    shares : {
        [key: string]: {
            '%': number,
            value: number,
            '%Acumulated': number
        }
    },
    total: number,
    'total_%': number,
    date: string
}

Now I have no problem with types
Thank you anyway!

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.