node.jstypescriptwebsocketws

Type does not satisfy the constraint of class it extends


I'm working on a WSS server using the Node ws library. Specifically, using the approach described in this question which may or may not be relevant.

I built a prototype server that works perfectly, but when I try to bring the same code across to my regular project, it doesn't work.

I wanted an easy way to identify the origin server for any websocket request:

import { Server, Data, WebSocket } from "ws";

interface IIdWebSocket extends WebSocket {
    id: string;
}

export class WSSServer {

    private wss = new Server<IIdWebSocket>({ port: 8090 });
     
    // and so on

Now the problem I have is that when I try to build this in my real project, I get the following message in the new Server<IIdWebSocket> line:

src/wws-server.ts:24:30 - error TS2344: Type 'IIdWebSocket' does not satisfy the constraint 'typeof WebSocket'.
  Type 'IIdWebSocket' is missing the following properties from type 'typeof WebSocket': prototype, createWebSocketStream, Server, WebSocketServer, and 9 more

I can't see an obvious difference between the version of the code that works and the version that doesn't. I notice that looking at the definitely typed source for the typescript library the property it is complaining about isn't a property of WebSocket at all - instead it appears to be a property of the Server type.

What is happening here?


Solution

  • It's expecting the type of a class constructor and you are passing it an object type. The value WebSocket is a class constructor, and so typeof WebSocket is the type for that constructor.

    type IIdWebSocketConstructor = typeof WebSocket & {
        new(): IIdWebSocket
    }
    
    interface IIdWebSocket extends WebSocket {
        id: string
    }
    

    This creates a constructor type that returns IIdWebSocket when constructed.

    export class WSSServer {
        private wss = new Server<IIdWebSocketConstructor>({ port: 8090 });
    
        testing123() {
            this.wss.on('connection', (socket) => {
                socket.id // works
                //     ^? number
            })
        }
    }
    

    See Playground