Как создать интерфейс объекта с предопределенными ключами? - PullRequest
1 голос
/ 20 января 2020

У меня есть объект с данными:

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

Я хочу преобразовать его в объект, ключ которого будет item.type:

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

Я определил enum с типами: enum GameTypes { 'soccer', 'running', 'hockey' }. И когда я пытаюсь использовать enum в качестве ключа объекта, я получаю сообщение об ошибке: Элемент неявно имеет тип 'any', потому что выражение типа GameTypes нельзя использовать для индексации типа 'GameProducts'. Свойство '[GameTypes.lottery]' не существует для типа 'GameProducts'.ts (7053)

Полный код:

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
  }, {})

Что я делаю не так? Есть ли другие способы сделать это?

1 Ответ

1 голос
/ 20 января 2020

Необходимо решить несколько проблем:

  • Не определен GameProduct, который, вероятно, следует заменить на Game
  • GameProducts - это карта в массив, а не простой объект
  • для того, чтобы редуктор понимал код и правильно его закреплял, проще использовать неизменяемый код, как показано ниже
  • Используйте необходимость использовать отображение GameTypes['some_value'] для транспилятора для подтверждения вашего кода.

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);

Вы также можете альтернативно использовать:

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

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

или более простое решение:

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

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

, которое будет работать так же хорошо .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...