Exploring the implementation of binding in a game engine, I aim to incorporate a touch of typing.
/** Engine external functions */
export type Message<TBody> = { }
// This function returns the same unique object for the same `s`
// An internal engine object solely for comparison from user code
declare function Message<TBody>(s: string): Message<TBody>;
declare function sendMessage<B>(message: Message<B>, body: B): void;
/** User code */
// Messages created by the user at initialization
const MessageMove: Message<{x: number, y: number}> = Message("move");
const MessageHit: Message<{damage: number}> = Message("hit");
// Correct resolution of types in sendMessage
sendMessage(MessageMove, {});
sendMessage(MessageHit, { damage: 100 });
// Numerous implementations required for the `recieveMessage` function
// Unsure how to tie body type to message without boilerplate code
class MyActor {
recieveMessage<B>(message: Message<B>, body: B) {
if (message === MessageMove) {
// Type of body is `B`, expected `{ x: number, y: number }`
console.log(body.x, body.y);
} else if (message === MessageHit) {
// Also expecting `B`
console.log(body.damage);
}
}
}
Although the declaration types can be altered, message
and body
must remain separate entities
Various tricks have been attempted but with no successful outcomes.
The current solution involves extensive function declarations each time.
recieveMessage(message: "a"|"b"|"c", body: message extends "a" ? ... : message extends "b" ...
Alternatively, long overloads could be used in the function.