In my project, I am developing a WebSocket component that requires the type Message
to have a mandatory property named type
.
export type Message = {
type: string;
[key: string]: any; // eslint-disable-line @typescript-eslint/no-explicit-any
};
This component is configured with a set of callback functions that are triggered whenever a Message
of the corresponding type
is received.
export interface Listeners {
[type: string]: (msg: Message) => void;
}
Here's a snippet of the WebSocket implementation code:
...
ws.onmessage = (event: MessageEvent): void => {
console.log("[websocket] got raw message", event.data);
try {
const msg = JSON.parse(event.data);
if (listeners[msg.type]) {
console.log("[websocket] got message", msg);
listeners[msg.type](msg);
}
}
}
...
When utilizing the WebSocket component, I aim to define a custom type as an extension of the base Message
type, which includes the type
property.
interface GraphMessage extends Message {
id: string;
type: "initial" | "update";
chartType: "line" | string;
data: GraphPoint[];
}
I want to use the component in the following way:
const handleUpdate = (msg: GraphMessage) => {}
const handleInitial = (msg: GraphMessage) => {}
const ws = await websocket("ws://localhost:9999/", {
initial: handleInitial,
update: handleUpdate
});
Unfortunately, I am encountering a Typescript error:
TS2322: Type '(msg: GraphMessage) => void' is not assignable to type '(msg: Message) => void'.
Types of parameters 'msg' and 'msg' are incompatible.
Type 'Message' is not assignable to type 'GraphMessage'.
To resolve this issue, I believe making Message
a generic type would be beneficial.
type Message<T> = {
type: string
[key: string]: any
} & T
interface GraphMessage {
graphName: string
}
type Callback = (msg: Message<GraphMessage>) => void
const myBaseMessage = {
t...