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<boolean>;
// The rest are Emitter properties, but without the `this` type
on<E extends keyof ServerToClientEvents>(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<E extends keyof ClientToServerEvents>(
event: E,
...args: Parameters<ClientToServerEvents[E]>
): void;
}
export function createSocket<
ServerToClientEvents extends EventsMap,
ClientToServerEvents extends EventsMap
>(address = "/ws"): Socket<ServerToClientEvents, ClientToServerEvents> {
const socket = new WebSocket(address);
const connected = ref<boolean>(false);
const emitter = createNanoEvents<ServerToClientEvents>();
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<K extends keyof ClientToServerEvents>(
event: K,
...args: Parameters<ClientToServerEvents[K]>
) {
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.