1

I have object with data:

const data = [
      {
        type: 'soccer',
        price: '$10'
      },
      {
        type: 'running',
        price: '$5'
      },
      {
        type: 'hockey',
        price: '$15'
      }
    ]

I want to convert it to object where key will be item.type:

const parsedData = {
  soccer: {
    type: 'soccer',
    price: '$10'
  },
  running: {
    type: 'running',
    price: '$5'
  },
  hockey: {
    type: 'hockey',
    price: '$15'
  }
}

I've defined enum with types: enum GameTypes { 'soccer', 'running', 'hockey' }. And when I trying to use enum as key of object I'm getting error: Element implicitly has an 'any' type because expression of type 'GameTypes' can't be used to index type 'GameProducts'. Property '[GameTypes.lottery]' does not exist on type 'GameProducts'.ts(7053)

Full code:

enum GameTypes { 'soccer', 'running', 'hockey' }

type Game = {
  type: GameTypes
  price: string
}

type GameProducts = { [key in GameTypes]?: Game } | {}

const data: Array<Game> = [
  {
    type: 'soccer',
    price: '$10'
  },
  {
    type: 'running',
    price: '$5'
  },
  {
    type: 'hockey',
    price: '$15'
  }
]

// trying to format games in object
const formatGames: GameProducts = data.reduce((acc | {}, item) => {
    if (!acc[item.type]) {  // <-- error here
      acc[item.type] = []
    }
    acc[item.type].push(item)

    return acc
  }, {})

What I'm doing wrong? Any other ways to do it?

slava_slava
  • 636
  • 1
  • 10
  • 23

1 Answers1

1

There's a few issues to resolve:

  • GameProduct is not defined, which should probably be replaced by Game
  • GameProducts is map to an array and not a simple object
  • for the reducer to understand the code, and lint it appropriately, it's easier to use immutable code like below
  • Use need to use the mapping GameTypes['some_value'] for the transpiler to acknowledge your code.

enum GameTypes { 'soccer', 'running', 'hockey' }

type Game = {
  type: GameTypes
  price: string
}

type GameProducts = { [key in GameTypes]?: Game[] };

const data: Array<Game> = [
  {
    type: GameTypes['soccer'],
    price: '$10'
  },
  {
    type: GameTypes['running'],
    price: '$5'
  },
  {
    type: GameTypes['hockey'],
    price: '$15'
  }
]

// formatting games object
const formatGames: GameProducts = data.reduce((acc: GameProducts, item) => {
    if (!acc[item.type]) {
        acc[item.type] = [];
    }

    acc[item.type] = [
        ...(acc[item.type] || []),
        item
    ];

    return acc
}, {});

console.log(formatGames);

You can also alternatively use:

enum GameTypes { Soccer = 'soccer', Running = 'running', Hockey = 'hockey' }

const data: Array<Game> = [
  {
    type: GameTypes.Soccer,
    price: '$10'
  }
]

Or a simpler solution:

type GameTypes = 'soccer' | 'running' | 'hockey';

const data: Array<Game> = [
  {
    type: 'soccer',
    price: '$10'
  }
]

Which would work just as fine.

Mor Shemesh
  • 2,689
  • 1
  • 24
  • 36
  • FYI, this also relates to this issue: https://stackoverflow.com/questions/15490560/create-an-enum-with-string-values – Mor Shemesh Jan 20 '20 at 14:19