Web sockets are pretty straight-foward, and using something like socket.io is probably overkill for the client-side. Here's a basic file you can just throw in the src/game folder (I named the file socket.ts) to use web sockets with proper typing:

import { createNanoEvents, EventsMap, Unsubscribe } from "nanoevents";import { Ref, ref } from "vue";export interface Socket< ServerToClientEvents extends EventsMap, ClientToServerEvents extends EventsMap> { socket: WebSocket; connected: Ref; // The rest are Emitter properties, but without the `this` type on(event: E, cb: ServerToClientEvents[E]): Unsubscribe; events: Partial<{ [E in keyof ServerToClientEvents]: ServerToClientEvents[E][] }>; // Note that `emit` uses a different type param than the others emit( event: E, ...args: Parameters ): void;}export function createSocket< ServerToClientEvents extends EventsMap, ClientToServerEvents extends EventsMap>(address = "/ws"): Socket { const socket = new WebSocket(address); const connected = ref(false); const emitter = createNanoEvents(); socket.onopen = () => { connected.value = true; }; socket.onmessage = event => { const [eventName, ...args] = JSON.parse(event.data); emitter.emit(eventName, ...args); }; socket.onclose = () => { connected.value = false; }; function emit( event: K, ...args: Parameters ) { if (connected.value) { socket.send(JSON.stringify([event, ...args])); } } return { socket, connected, ...emitter, emit };}

You could then use it like this:

const sockets = createSocket< { ping: (foo: string) => void; }, { pong: (foo: string) => void; }>();sockets.on("ping", foo => { console.log("ping received", foo); sockets.emit("pong", foo);});

The on function will have proper type inferencing for the defined events. The socket will also expose the WebSocket instance itself and a ref for whether or not you're currently connected.



Discuss this on our forum.