Pesquisa de site

Função TypeScript que aceita um array de strings e retorna um objeto com as strings fornecidas como chaves


Como alguém poderia tipar corretamente o seguinte método:

const getVars = (vars: string[]) => {
  const data = [
    {
      "someId": "28",
      "someAttr": "2",
    },
    {
      "someId": "43",
      "someOtherAttr": "3",
    },
    {
      "someOtherId": "32",
      "someAttr": "4",
    }
  ] // an array containing some data

  const result = vars.reduce((acc, _var) => ({
    ...acc,
    ...data.reduce((acc, acc) => ({
      ...acc,
      [...acc[_var], curr[_var]]
    }, {})
  }), {})

  return result
}

uso :

const { someId, someAttr } = getVars(['someId', 'someAttr'])

saída: someId: ['28', '43'], someAttr: ['2', '4']

Eu gostaria de tipar em TypeScript getVars para que o tipo de retorno refletisse os parâmetros fornecidos, por exemplo, se eu passar ['someId'] como parâmetro, o TypeScript saberia que a função retorna um objeto com a chave 'someId'.

Resposta #1

Você pode digitar isso de uma forma meio estrita ou muito estrita. Depende de quanta informação você conhece de antemão (você conhece as chaves dos elementos de data?) e o quão maluco você quer ser. Seu data aqui é um array de objects com chaves string. Os valores são sempre string? Ou eles só acontecem de ser assim neste exemplo?

Para a abordagem meio que estrita, estou assumindo que os valores são sempre string e que data tem o tipo Record<string, string>[].

Queremos saber os valores específicos de string que passamos para getVars, então usaremos um genérico T extends string. Retornamos um objeto que tem essas strings específicas T como chaves e os valores são um array de strings. Então, o tipo de retorno é Record<T, string[]>.

Quando você está construindo um objeto através de reduce(), você precisa usar as para afirmar o tipo do objeto final.

const getVars = <T extends string>(vars: T[]): Record<T, string[]> => {
    return vars.reduce((acc, _var) => ({
        ...acc,
        [_var]: data.map(o => o[_var]).filter(v => v !== undefined)
    }), {} as Record<T, string[]>);
}

const { someId, someAttr } = getVars(['someId', 'someAttr'])
console.log(someId, someAttr);

Link para o Playground do Typescript

Resposta #2

const data = [
    {
      "someId": "28",
      "someAttr": "2",
    },
    {
      "someId": "43",
      "someOtherAttr": "3",
    },
    {
      "someOtherId": "32",
      "someAttr": "4",
    }
  ];

const getVars = (data, vars) => {
  return data.reduce((acc, curr) => {
    Object.keys(curr).filter(key => vars.includes(key)).forEach(
      key => acc[key] = [...(acc[key] || []), curr[key]],
    );
    
    return acc;
  }, {});
}

console.log(getVars(data, ['someId', 'someAttr']));

Artigos relacionados