4

Is it possible to convert a union type to a map with the key being "type" property? e.g. Given a union type Actions:

type Actions =
  | {
      type: 'campaignCreated';
      code: string;
    }
  | {
      type: 'campaignEnded';
      amount: number;
    };

I'd like to be able to receive;

type ActionMap = {
  campaignCreated: {
    type: 'campaignCreated';
    code: string;
  };
  campaignEnded: {
    type: 'campaignEnded';
    amount: number;
  };
};
Machycek
  • 863
  • 1
  • 6
  • 7

1 Answers1

7

Yes it's possible.

We start with a type for selecting a single union member based on the type type:

type ActionSelector<T extends Actions['type'], U extends {type: Actions['type']}> = 
    U extends {type: T} ? U : never;

It works because conditional types distribute the condition over the members of the union type, when the condition argument is a union.

Just a check that it works as expected:

type A1 = ActionSelector<'campaignCreated', Actions>

Then we can use it as 'value type' in a mapped type:

type ActionMap = {[t in Actions['type']]: ActionSelector<t, Actions>};

the result is

type ActionMap = {
    campaignCreated: {
        type: "campaignCreated";
        code: string;
    };
    campaignEnded: {
        type: "campaignEnded";
        amount: number;
    };
}
artem
  • 46,476
  • 8
  • 74
  • 78