Reputation: 15003
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.
Upvotes: 4
Views: 163
Reputation: 925
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
Upvotes: 3
Reputation: 2182
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)
}
}
Upvotes: 1