I'm currently working on getting a WebSocket server running on NodeJs with TypeScript. As a WebSocket server implementation, I am using ws. Along with that I use the @types/ws package for the typings. I want the server to periodically send out a ping package to every connected client. The readme file of the ws module already provides an example implementation in JavaScript which I would like to use aswell. You can find the example implementation here:
The problem I am facing is that the sample implementation adds the "isAlive" attribute to a socket object which I obviously can not do in TypeScript since the "isAlive" attribute does not exist for the socket class.
My question: What is the best way to add this attribute to the socket class? Since I pass these socket objects around as parameters, I want to avoid adding some sort of extra import to all my files that somehow work with a socket.
I want to avoid typecasting the socket object to any for this.
I try to implement a wrapper class around ws, so that I can just instanciate my WebSocket class and use it throughout my application.
My class looks like this
import * as ws from "ws";
export default class WebSocketServer {
private wss: ws.Server;
private onSubscription: (socket: ws, deviceId: string, topicFilter: string) => void;
constructor(port: number, onSubscription: (socket: ws, deviceId: string, topicFilter: string) => void) {
this.wss = new ws.Server({ port });
this.onSubscription = onSubscription;
const conhandler = this.handleConnection.bind(this);
this.wss.on("connection", conhandler);
}
public static init(onSubscription: (socket: ws, deviceId: string, topicFilter: string) => void): WebSocketServer {
const port: number = Number(process.env.WSS_PORT);
if (!port) {
throw new Error("Unable to create the WebSocket server: Environment variable \"WSS_PORT\" is missing");
}
const server: WebSocketServer = new WebSocketServer(port, onSubscription);
console.info(`Websocket Server listening on port ${port}`);
return server;
}
private handleConnection(socket: ws): void {
const messageHandler: (socket: ws, data: ws.Data) => void = this.handleMessage.bind(this);
socket.on("message", data => messageHandler(socket, data));
/* This is where I try to add the isAlive attribute to a socket object */
/* but since ws does not have an attribute isAlive, TypeScript complains */
socket.on("pong", () => socket.isAlive = true);
}
private handleMessage(socket: ws, data: ws.Data): void {
/* Do stuff with the message */
}
public quit() {
this.wss.close();
}
}
Edit
As mentioned by a commenter, i tried declaration merging. I created a new file called "Augment.ts" and added the following code:
import * as ws from "ws";
declare module "ws" {
interface WebSocket {
isAlive: boolean;
}
}
In the file that contains my WebSocketServer class, i added the import for the Augment.ts file like so: import "./Augment"
. The result is another error message (but somehow stating the same?):
Property 'isAlive' does not exist on type 'import("c:/path/to/project/node_modules/@types/ws/index.d.ts")'.ts(2339)