DarkLite1
DarkLite1

Reputation: 14705

groupBy that is TypeScript safe

Given all the answers already out there we tried to create a groupBy arrow function that doesn't complain about TypeScript errors. with guidance from this answer and this one we already have this working code:

const groupBy = <TItem>(
  items: TItem[],
  key: string
): { [key: string]: TItem[] } =>
  items.reduce(
    (result, item) => ({
      ...result,
      [item[key]]: [...(result[item[key]] || []), item],
    }),
    {}
  )

However, it still complains: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'unknown'.
No index signature with a parameter of type 'string' was found on type 'unknown'.

It is indeed possible that the used key is empty/blank. So TypeScript is not wrong here. So in that case it should simply use a placeholder value like NA or something.

What is the correct way to create a reusable error free typescript version for this groupBy function?

Upvotes: 3

Views: 1093

Answers (1)

Aplet123
Aplet123

Reputation: 35512

Use some generics to lower down the key type and force the object to contain the key:

type ObjectKey = string | number | symbol;

const groupBy = <K extends ObjectKey, TItem extends Record<K, ObjectKey>>(
  items: TItem[],
  key: K
): Record<ObjectKey, TItem[]> =>
  items.reduce(
    (result, item) => ({
      ...result,
      [item[key]]: [...(result[item[key]] || []), item],
    }),
    {} as Record<ObjectKey, TItem[]>
  );

Playground link

Upvotes: 5

Related Questions