Typescript-funktion som tar emot en array av strängar och returnerar ett objekt med givna strängar som nycklar
Hur skulle man korrekt typescripta följande metod:
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
}
användning :
const { someId, someAttr } = getVars(['someId', 'someAttr'])
output: someId: ['28', '43'], someAttr: ['2', '4']
Jag skulle vilja typescripta getVars så att returtypen speglar givna parametrar, till exempel, om jag skickar ['someId'] som parameter, skulle typescript veta att funktionen returnerar ett objekt med nyckeln 'someId'.
Svar #1
Du kan skriva detta på ett slags-sätt strikt eller mycket strikt. Det beror på hur mycket information du vet från början (vet du nycklarna för elementen i data?) och hur galen du vill vara. Din data här är en array av objects med string-nycklar. Är värdena alltid string? Eller råkar de bara vara det i detta exempel?
För den typ av halv-strikta tillvägagångssättet antar jag att värdena alltid är string och att data har typen Record<string, string>[].
Vi vill veta de specifika strängvärden som vi skickade till getVars, så vi kommer att använda en generisk T extends string. Vi returnerar ett objekt som har dessa specifika strängar T som nycklar och värdena är en array av strängar. Så returtypen är Record<T, string[]>.
När du bygger ett objekt genom reduce() behöver du använda as för att fastställa typen på det slutliga objektet.
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);
Typescript Playground-länk
Svar #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']));
