Home > other >  Record of discriminated union
Record of discriminated union

Time:06-12

Taken this structured messages:

type MessageVariant<T extends string, P = {}> = {
  type: T;
  payload: P;
};

type BoundsChangedMessage = MessageVariant<
  "bounds_changed",
  {
    bounds: number[][];
  }
>;

type ChangeLayoutMessage = MessageVariant<
  "change_layout",
  {
    name: string;
  }
>;

type Message = BoundsChangedMessage | ChangeLayoutMessage;

I want to be able to express a strong record of:

const handlers: MessageHandler = {
  bounds_changed: (message/*: BoundsChangedMessage*/) => {},
  change_layout: (message/*: ChangeLayoutMessage*/) => {},
};

So far I have been trying various attempts without luck, including:

type MessageHandler = {
  [T in Message["type"]]: (message: MessageVariant<T, /* Payload? */>) => void;
}

Here is a TS Playground for the example.

CodePudding user response:

You need to use Key mapping via "as" and change your MessageHandler type definition to the following

type Message = BoundsChangedMessage | ChangeLayoutMessage;

type MessageHandler = {
  [M in Message as M["type"]]: (message: M) => void;
}

Here is the link to TS Playground with the full example

CodePudding user response:

You can achieve that record type by defining the message handler type like below.

type Message = BoundsChangedMessage | ChangeLayoutMessage;

type MessageHandler = {
  [K in Message as K['type']]: (message: K) => void;
}

const handlers: MessageHandler = {
  bounds_changed: m => {
    console.log(m);
  },
  change_layout: m => {
    console.log(m)
  }
}
  • Related