user1346765
user1346765

Reputation: 122

Typescript function that accepts array of strings and returns object with given strings as keys

How could one properly typescript the following method:

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
}

usage:

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

output: someId: ['28', '43'], someAttr: ['2', '4']

I'd like to typescript getVars so the return type would reflect given parameters, for example, if I pass ['someId'] as parameter, the typescript would know the function returns an object with key 'someId'.

Upvotes: 3

Views: 1334

Answers (2)

Linda Paiste
Linda Paiste

Reputation: 42198

You can type this kinda-sorta strictly or very strictly. It depends on how much information you know up front (do you know the keys of the elements of data?) and how crazy you want to be. Your data here is an array of objects with string keys. Are the values always string? Or do they just happen to be in this example?

For the kinda-sorta strict approach, I am assuming that the values are always string and that data has type Record<string, string>[].

We want to know the specific string values that we passed to getVars, so we will use a generic T extends string. We return an object that has those specific strings T as keys and the values are an array of strings. So the return type is Record<T, string[]>.

When you are building an object through reduce() you need to use as to assert the type of the final object.

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 Link

Upvotes: 6

MoxxiManagarm
MoxxiManagarm

Reputation: 9124

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

Upvotes: -1

Related Questions