0

I have a reduced function that needs initial values based on an enum. See simplified code below:

items.reduce<Record<RoleType, Community[]>>(
    (acc, community) => {
        ... // this works
    },
    { [RoleType.LEADER]: [], [RoleType.FACILITATOR]: [], [RoleType.EDITOR]: [], [RoleType.EXPERT]: [], [RoleType.MEMBER]: [] }
);

The enum looks like this:

export enum RoleType {
    EXPERT = 'EXPERT',
    LEADER = 'LEADER',
    FACILITATOR = 'FACILITATOR',
    EDITOR = 'EDITOR',
    MEMBER = 'MEMBER'
}

I don't want to explicitely list every member of the enum though. I tried with the following:

{ ...Object.values(RoleType).map((role) => ({ [role]: [] })) }

Is there a way to simply add empty arrays for all of the enum's members? Best case would be if there was proper typing too.

My attempt above throws this error (which I really don't know what to do with):

Type '{ [n: number]: { [x: string]: any[]; }; length: number; toString(): string; toLocaleString(): string; pop(): { [x: string]: any[]; }; push(...items: { [x: string]: any[]; }[]): number; concat(...items: ConcatArray<{ [x: string]: any[]; }>[]): { ...; }[]; concat(...items: ({ ...; } | ConcatArray<...>)[]): { ...; }[];...' is missing the following properties from type 'Record<RoleType, Community[]>': EXPERT, LEADER, FACILITATOR, EDITOR, MEMBER

sandrooco
  • 8,016
  • 9
  • 48
  • 86

2 Answers2

1
{ ...Object.values(RoleType).map((role) => ({ [role]: [] })) }

will create an object with indices of the array as key.

{
  "0": { "EXPERT": [] },
  "1": { "LEADER": [] },
  "2": { "FACILITATOR": [] }
  ...
}

You need to use something like this:

Object.assign({}, ...Object.values(RoleType).map(r => ({ [r]: [] })))
adiga
  • 34,372
  • 9
  • 61
  • 83
  • This works - but why? :D Can you elaborate? – sandrooco Jul 06 '21 at 11:06
  • @sandrooco You already know `Object.values(..).map(..)` creates an array of objects with each object having `RoleType` key. When you spread that array of objects, it becomes, `Object.assign({}, { "EXPERT": [] }, { "LEADER": [] }, { "FACILITATOR": [] }, etc)`. It merges them all to a single object. A similar question I had answered earlier: https://stackoverflow.com/a/67303414. – adiga Jul 06 '21 at 12:19
  • That makes sense, thanks for the explanation. Seems obvious as soon as you understand it. – sandrooco Jul 06 '21 at 12:37
1

I have made a TS transformer that allows you to grab, amongst others, all values of an enum - it's called ts-reflection and it works like this:

enum MyEnum {
  NO = 0,
  MAYBE = 1,
  YES = 2
}

const valuesOfMyEnum = valuesOf<MyEnum>(); // [0, 1, 2]

Here's how you set it up

Ján Jakub Naništa
  • 1,880
  • 11
  • 12