6

I've recently began using TypeScript on my own projects, though I'm not sure how I should go about getting my code to work.

Object.entries(data[`set_${id}`].tiles).map(([tileType, tiles]) => (
  tiles.map(([left, top]), index) => (
     //rest of code
  )
))

TypeScript is complaining that left, top, and index all have 'any' type. How can I go about assigning types in this configuration?

data.json Structure:

{
  "set_1": {
    "tiles": {
       "typeA": [[0, 1], [0, 2]],
       "typeB": [[2, 0], [2, 1]]
    }
  }
}

Any advice would be greatly appreciated.

Thanks!

UK_Kefka
  • 211
  • 1
  • 3
  • 7

4 Answers4

5

This is what worked best for me:

export function objectEntries<
  T extends Record<PropertyKey, unknown>,
  K extends keyof T,
  V extends T[K]
>(o: T) {
  return Object.entries(o) as [K, V][];
}
PaulHendrickson
  • 190
  • 2
  • 7
  • 1
    Great solution, thanks! I believe it's also possible to change it a bit: `T extends { [key: string | number | symbol]: unknown},` – barinbritva Mar 13 '23 at 12:23
  • Yes, that probably works better, thank you! – PaulHendrickson Mar 15 '23 at 18:53
  • 1
    Use `PropertyKey` or `keyof any` if you want a shorter alternative to `string | number | symbol`. They mean the same thing. – kelsny Mar 15 '23 at 18:57
  • It's crazy that typescript still doesn't understand how to work with many functions. I still have to use this hack today in mid 2023. – off99555 Jul 22 '23 at 11:07
1

I was able to get it to work quickly by repeating the types:

for (const [k, v] of (Object.entries(o) as [number, any][]))
// typeof(k) === 'number'
// typeof(v) === 'any'

Sometimes you have to cast to unknown first, though:

for (const [k, v] of (Object.entries(o) as unknown as [number, any][]))

You can wrap this up into a utility function as well:

function objectEntries<K extends (string | number | symbol), V>(o: Record<K, V>) {
  return Object.entries(o) as unknown as [K, V][];
}

for (const [k, v] of objectEntries(o))
// typeof(k) matches key type of 'o'
// typeof(v) matches value type of 'o'

EDIT: The reason why this isn't done automatically is explained in this answer.

Malvineous
  • 25,144
  • 16
  • 116
  • 151
0

Solved it. Achieved by doing:

Object.entries(data[`set_${id}`].tiles).map(([tileType, tiles]) => (
  tiles.map(([left, top] : number[], index : number) => (
     //rest of code
  )
))
UK_Kefka
  • 211
  • 1
  • 3
  • 7
-1

You can set them in this way:

Object.entries(data[`set_${id}`].tiles).map(([tileType, tiles]) => (
  tiles.map(([left: number, top: number]), index: number) => (
     //rest of code
  )
))
Ehsan Mahmud
  • 725
  • 4
  • 11