Ошибка обобщения, имя переменной не существует для типа T

у меня проблема с дженериками машинописного текста. вот код:

интерфейс:

export interface Hero {
  id: number
  name: string
  localized_name: string
  avatar: string
}

export interface Item {
  id: number
  name: string
  cost: number
  secret_shop: boolean
  side_shop: boolean
  recipe: boolean
  localized_name: string
  avatar: string
}

сама функция

export const getContent = async <T>(genre: string): Promise<T[]> => {
  const res = await fetch(`${apiEndpoint}${genre})
  const response = await res.json()
  const defaultContent = response.result[category]
  const contentWithImage = defaultContent.map((item: T) => {
    const contentImageUrl = `${imgURL}${item.name.replace('__', '')}.png`

    return { ...item,  avatar: contentImageUrl }
  })
  return contentWithImage
}

называется так:

const heroes = await getContent<Hero>('heroes')

or

const items = await getContent<Hero>('items')

я получаю, что имя не определено по типу (для элемента на карте), и я действительно его не понимаю

если есть подсказки спасибо


person Hervé    schedule 24.07.2019    source источник


Ответы (1)


Если вы хотите иметь доступ к свойствам T, вам нужно будет добавить ограничение. Ограничение гарантирует, что любой переданный аргумент соответствует требованиям ограничения.

export const getContent = async <T extends { name : string }>(genre: string): Promise<T[]> => {
  const res = await fetch(`${apiEndpoint}${genre}`)
  const response = await res.json()
  const defaultContent = response.result[category]
  const contentWithImage = defaultContent.map((item: T) => {
    const contentImageUrl = `${imgURL}${item.name.replace('__', '')}.png`

    return { ...item,  avatar: contentImageUrl }
  })
  return contentWithImage
}

Обычно не рекомендуется иметь параметры универсального типа, которые должны быть указаны явно. Если у вас есть только эти два варианта, перегрузки могут быть лучшим выбором:


async function getContent (genre: "heroes"): Promise<Hero[]>
async function getContent (genre: "items"): Promise<Item[]> 
async function getContent (genre: string): Promise<(Item | Hero)[]>{
  const res = await fetch(`${apiEndpoint}${genre}`)
  const response = await res.json()
  const defaultContent = response.result[category]
  const contentWithImage = defaultContent.map((item: Item | Hero) => {
    const contentImageUrl = `${imgURL}${item.name.replace('__', '')}.png`

    return { ...item,  avatar: contentImageUrl }
  })
  return contentWithImage
}

person Titian Cernicova-Dragomir    schedule 24.07.2019
comment
Хммм, понятно, нет ли способа убедиться, что моя переменная item имеет тип Hero или Item в зависимости от <T>? потому что для меня это то, что item: T означает, но я должен ошибаться - person Hervé; 24.07.2019
comment
@Hervé вы могли бы пойти с перегрузками .. я добавлю версию - person Titian Cernicova-Dragomir; 24.07.2019
comment
@Hervé добавил версию - person Titian Cernicova-Dragomir; 24.07.2019
comment
Большое спасибо ! Паттерн совсем нехороший, но речь шла чисто о дженериках. Я бы разделил на два метода, если бы этот код должен был пойти в производство;) - person Hervé; 24.07.2019
comment
Вы можете сделать ограничение T extends (Hero | Item) или извлечь общий интерфейс INamed из обоих и использовать его в ограничении. - person dezfowler; 25.07.2019