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