websocket 类型不满足它扩展的类的约束

2wnc66cl  于 2024-01-09  发布在  其他
关注(0)|答案(2)|浏览(141)

我正在使用Node ws库的WSS服务器上工作。具体来说,使用in this question描述的方法,可能相关,也可能不相关。
我构建了一个工作完美的原型服务器,但是当我试图将相同的代码引入到我的常规项目中时,它不起作用。
我想要一种简单的方法来识别任何WebSocket请求的源服务器:

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

字符串
现在我遇到的问题是,当我试图在我的真实的项目中构建这个时,我在new Server<IIdWebSocket>行中得到以下消息:

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


我看不出运行的代码版本和不运行的代码版本之间有什么明显的区别。我注意到,查看definitely typed source for the typescript library,它所抱怨的属性根本不是WebSocket的属性-相反,它似乎是Server类型的属性。
这是怎么回事?

mfpqipee

mfpqipee1#

它需要一个类 * 构造函数 * 的类型,而你传递给它一个对象类型。值WebSocket是一个类构造函数,所以typeof WebSocket是该构造函数的类型。

type IIdWebSocketConstructor = typeof WebSocket & {
    new(): IIdWebSocket
}

interface IIdWebSocket extends WebSocket {
    id: string
}

字符串
这将创建一个构造函数类型,在构造时返回IIdWebSocket

export class WSSServer {
    private wss = new Server<IIdWebSocketConstructor>({ port: 8090 });

    testing123() {
        this.wss.on('connection', (socket) => {
            socket.id // works
            //     ^? number
        })
    }
}


查看Playground

5cg8jx4n

5cg8jx4n2#

被接受的答案实际上只是对类型系统撒谎。创建的WebSocket的类型仍然是默认类型,这意味着即使你声称它有一个id属性,实际上也不会有。你应该创建一个WebSocket的实际子类。

// `id` will be `undefined`
wss.on('connection', (ws) => console.log(ws.id.toUpperCase())

字符串
注意服务器的类型参数:

class Server<
        T extends typeof WebSocket.WebSocket = typeof WebSocket.WebSocket,
        U extends typeof IncomingMessage = typeof IncomingMessage,
    > extends EventEmitter {


它不是T extends WebSocket.WebSocket,而是T extends typeof WebSocket.WebSockettypeof SomeClass给你的是类对象的类型(构造函数),而不是类的示例的类型。因此,在扩展原始WebSocket类之后,泛型类型参数应该是Server<typeof CustomWebSocket>
还要注意构造函数参数WebSockethttps://github.com/websockets/ws/blob/a57e963f946860f6418baaa55b307bfa7d0bc143/lib/websocket-server.js#L382
完整示例:

import { Server, WebSocket } from 'ws'

export class CustomWebSocket extends WebSocket {
  userId!: string

  sendStuff() {
    this.send('stuff')
  }
}

export class CustomWebsocketServer extends Server<typeof CustomWebSocket> {
  constructor() {
    super({
      WebSocket: CustomWebSocket,
    })
  }

  socketForUser(userId: string): CustomWebSocket | undefined {
    // this.clients is of type Set<CustomWebSocket>
    for (const socket of this.clients) {
      if (socket.userId === userId) {
        return socket
      }
    }
  }
}

const wss = new CustomWebsocketServer()

wss.on('connection', (socket) => {
  // socket is of type CustomWebSocket
  socket.sendStuff()
})


最后说明:你不需要一个,但是如果你给WebSocket子类添加一个构造函数,它必须与原始WebSocket类的构造函数兼容,从技术上讲,这是:

constructor(...params: ConstructorParameters<typeof WebSocket>) {}

相关问题