In order to manage messaging between the browser and a web worker, I have developed a generic class. Each side creates a class that can send specific messages and acknowledge them on the other side with a returned result in a payload. The implementation is currently working perfectly, and I've implemented an interface mapping to facilitate message sending.
However, I am facing a challenge when it comes to inferring the return type based on the interface mapping passed as an argument to the function.
Below is a link to the playground showcasing the interfaces, classes, and their implementations.
I am specifically struggling with the 'send' function:
messages.send({ action: MessageAction.Init, data: { scripts: [] } }).then(data => {
// need to infer the return type from the action.
console.log(data);
});
Essentially, instead of returning void from the playground, I would like it to automatically determine that 'data' is actually
AcknowledgeMessageData<InitReturn>
because the 'action' property of the argument is 'init' (currently not generic). Therefore, the object structure should look like this:
{
isSuccess: true,
result: {
someRandomProperty: '',
anotherProperty: 0
}
}
Different actions would lead to different generic properties for 'result'.
Currently, I'm unable to figure out how to trigger the inference based on the argument's property and apply it to the return value's property.
Edit: added minimal reproduction
enum Action {
Ack = 'ack',
Init = 'init'
}
interface BaseMessage {
action: Action;
}
interface AckBaseMessage extends BaseMessage {
action: Action.Ack;
}
interface InitBaseMessage extends BaseMessage {
action: Action.Init;
}
interface MessageDataMapping {
[Action.Ack]: AckBaseMessage;
[Action.Init]: InitBaseMessage;
}
export type Message = { [K in Action]: MessageDataMapping[K] }[Action];
async function send(payload: Message) {
return thisWouldBeReturnedFromWebWorker(payload);
}
async function thisWouldBeReturnedFromWebWorker(payload: Message): Promise<any> {
if (payload.action === Action.Init) {
return {
action: Action.Init,
result: {
somePropertiesHere: true
}
};
}
return { action: Action.Ack, result: { isSuccess: true } }
}
send({ action: Action.Init }).then(response => {
response.result.somePropertiesHere
response.result.isSuccess
});