Pesquisa de site

typescript - Tipo 'string' não pode ser usado para indexar o tipo 'T'.ts(2536)


Estou recebendo o erro acima em result[key] em

type DataType = Record<string, number>
export function getDifference<T extends DataType>(data1: T, data2: T): T {
  const keys = Object.keys(data1)
  return keys.reduce<T>((result, key) => {
    result[key] = data1[key] - data2[key]
    return result
  }, {})
}

Como faço para me livrar disso enquanto ainda retorno um tipo genérico T para que as funções consumidoras ainda recebam o tipo correto (em vez de simplesmente mudar T para DataType).

Resposta #1

Você precisa definir o tipo correto para keys, assim como para result[key] e {} manualmente, já que o TypeScript não consegue identificá-los corretamente automaticamente.

type DataType = Record<string, number>
export function getDifference<T extends DataType>(data1: T, data2: T): T {
  const keys: (keyof T)[] = Object.keys(data1)
  return keys.reduce<T>((result, key) => {
    if(typeof data1[key] === "number" && typeof data2[key]) { // Safeguard against object, array, etc. properties
        result[key] = data1[key] - data2[key] as T[keyof T]
    }
    return result
  }, {} as T)
}
``

Resposta #2

Para aqueles com o desafio semelhante de transformar um Record<string, string> em vez de Record<string, number>, você precisa de um as extra na atribuição à chave específica. Aqui está o que funciona:

function transformRecords<T extends Record<string, string>>(
  records: T
): T {
  const keys: (keyof T)[] = Object.keys(records)
  return keys.reduce(
    (results, key) => {
      results[key] = records[key] + ' lol' as T[keyof T]
      return results
    },
    {} as T
  )
}

Você pode evitar o as extra se retornar um novo objeto em vez de mutar:

function transformRecords<T extends Record<string, string>>(
  records: T
): T {
  const keys: (keyof T)[] = Object.keys(records)
  return keys.reduce(
    (results, key) => ({
      ...results,
      [key]: records[key] + 'lol',
    }),
    {} as T
  )
}

E se você estiver transformando com promessas:

async function transformRecords<T extends Record<string, string>>(
  records: T
): Promise<T> {
  const keys: (keyof T)[] = Object.keys(records)
  return await keys.reduce(
    async (results, key) => ({
      ...await results,
      [key]: records[key] + 'lol'
    }),
    Promise.resolve({} as T)
  )
}

Artigos relacionados