I'm trying to model my data in Typescript in the following manner. Main focus is the type MessageHandler
that maps the type
in a message with a callback that accepts that message. I followed the handbook chapter for mapped types
type BaseMessageBody = {
msg_id?: number;
in_reply_to?: number;
};
type BaseMessage<TBody> = {
src: string;
dest: string;
body: BaseMessageBody & TBody;
};
type BroadcastMessage = BaseMessage<{
type: 'broadcast';
message: number;
}>;
type InitMessage = BaseMessage<{
type: 'init';
node_id: string;
node_ids: string[];
}>;
type Message = BroadcastMessage | InitMessage;
type Body = Message['body'];
type MessageHandler = {
[M in Message as M['body']['type']]?: (message: M) => void;
};
So far so good. The expanded type of MessageHandler is
type MessageHandler = {
broadcast?: ((message: BroadcastMessage) => void) | undefined;
init?: ((message: InitMessage) => void) | undefined;
}
But when I try to actually use the type like below:
const handlers: MessageHandler = {};
export const handle = (message: Message) => {
if (message.body.type === 'init') {
console.log('Initialized');
}
const handler = handlers[message.body.type];
if (!handler) {
console.warn('Unable to handle type', message.body.type);
return;
}
handler(message); //Error here
};
I get the following error. Somehow the handler type has transformed to const handler: (message: BroadcastMessage & InitMessage) => void
error: TS2345 [ERROR]: Argument of type 'Message' is not assignable to parameter of type 'BroadcastMessage & InitMessage'.
Type 'BroadcastMessage' is not assignable to type 'BroadcastMessage & InitMessage'.
Type 'BroadcastMessage' is not assignable to type 'InitMessage'.
Types of property 'body' are incompatible.
Type 'BaseMessageBody & { type: "broadcast"; message: number; }' is not assignable to type 'BaseMessageBody & { type: "init"; node_id: string; node_ids: string[]; }'.
Type 'BaseMessageBody & { type: "broadcast"; message: number; }' is missing the following properties from type '{ type: "init"; node_id: string; node_ids: string[]; }': node_id, node_ids
handler(message);
~~~~~~~
There are slightly related questions on stack overflow but I wasn't able to resolve my problem by following them. Here is the playground with all the code.