You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript WebSocket客户端绑定类方法报错:listener参数无效

解决TypeScript中WebSocket事件监听传入类方法报错的问题

问题描述

我是TypeScript新手,想用TypeScript结合websocket库创建WebSocket客户端。当前代码中,将箭头函数传入this.client.on("connect", this.handleConnection);可正常运行,但直接传入this.handleConnection方法时会抛出以下错误:

错误信息

TypeError [ERR_INVALID_ARG_TYPE]: The "listener" argument must be of type function. Received undefined
at checkListener (node:events:265:3)
at _addListener (node:events:545:3)
at WebSocketConnection.addListener (node:events:604:10)
at WebSocketClient.handleConnection (/home/mohammad/projects/alphaTrader/digestion/wsConnector.ts:57:25)
at WebSocketClient.emit (node:events:512:28)
at WebSocketClient.emit (node:domain:489:12)
at WebSocketClient.succeedHandshake (/home/mohammad/projects/alphaTrader/digestion/node_modules/websocket/lib/WebSocketClient.js:348:10)
at WebSocketClient.validateHandshake (/home/mohammad/projects/alphaTrader/digestion/node_modules/websocket/lib/WebSocketClient.js:332:10)
at ClientRequest.handleRequestUpgrade (/home/mohammad/projects/alphaTrader/digestion/node_modules/websocket/lib/WebSocketClient.js:261:14)
at ClientRequest.emit (node:events:512:28) {
code: 'ERR_INVALID_ARG_TYPE'
}

完整代码

import { Logger } from "./logger";


enum WebsocketStatus{
    CONNECTING = 'connecting',
    STOPPED = 'stopped',
    CONNECTED= 'connected',
    IDLE = 'idle'
}
interface WebsocketInterface{
    getStatus(): WebsocketStatus
    connect(): void
    disconnect(): void
    sendMessage(message: string): void
}

export class WebsocketClient implements WebsocketInterface{
    private status: WebsocketStatus;
    private url: string;
    private logger?: Logger;
    private client: webSocket.client;
    private connection?: webSocket.connection;
    constructor(url: string, logger?: Logger){
        if(logger)
            this.logger = logger;
        this.url = url;
        this.status = WebsocketStatus.IDLE;
        this.client = new webSocket.client();
        this.client.on("connectFailed", this.handleConnectionFailed);
        this.client.on("connect", this.handleConnection);
    }
    getStatus(): WebsocketStatus {
        return this.status;
    }
    connect(): void {
        this.client.connect(this.url);
    }
    disconnect(): void {
        this.connection?.close()
    }
    private handleConnectionFailed(error: Error){
        this.logger?.logError(error.message);
    }
    private handleConnection(connection: webSocket.connection){
        this.connection = connection;
        this.logger?.logInfo(`successfully connected to address ${this.url}`);
        this.connection.on("error", this.handleConnectionError);
        this.connection.on("close", this.handleConnectionClose);
        this.connection.on("message", this.handleConnectionMessage);
    }
    private handleConnectionError(error:Error){
        this.logger?.logError(error.toString());
        this.status = WebsocketStatus.STOPPED;
        this.connection?.close();
    }
    private handleConnectionClose(){
        this.logger?.logInfo("connection closed");
        this.status = WebsocketStatus.STOPPED;
        this.connection?.close();
    }
    private handleConnectionMessage(message: webSocket.Message){
        this.logger?.logInfo(message.toString());

    }
    sendMessage(message: string): void {
        this.connection?.send(message);
    }
}

问题原因

直接传入类方法时,方法的this指向会在事件触发时改变,不再指向WebsocketClient的实例。比如client.on("connect", this.handleConnection),当connect事件触发时,handleConnection里的this会指向client对象,而非你的类实例。这导致handleConnection内部调用this.connection.on("error", this.handleConnectionError)时,this.handleConnectionError是undefined(因为client没有这个方法),所以抛出listener为undefined的错误。

箭头函数能正常运行是因为它没有自己的this,会继承外层作用域的this(即构造函数中的类实例),所以方法内部的this始终指向类实例。

解决方案

方法一:构造函数中手动绑定this

在构造函数里给每个用作回调的方法绑定类实例的this,确保方法被调用时this始终指向类实例:

constructor(url: string, logger?: Logger){
    if(logger)
        this.logger = logger;
    this.url = url;
    this.status = WebsocketStatus.IDLE;
    this.client = new webSocket.client();
    
    // 绑定this到类实例
    this.handleConnectionFailed = this.handleConnectionFailed.bind(this);
    this.handleConnection = this.handleConnection.bind(this);
    this.handleConnectionError = this.handleConnectionError.bind(this);
    this.handleConnectionClose = this.handleConnectionClose.bind(this);
    this.handleConnectionMessage = this.handleConnectionMessage.bind(this);
    
    this.client.on("connectFailed", this.handleConnectionFailed);
    this.client.on("connect", this.handleConnection);
}

方法二:用箭头函数定义类方法

将类中的方法改为箭头函数形式,箭头函数会自动绑定当前类实例的this,无需手动绑定:

private handleConnectionFailed = (error: Error) => {
    this.logger?.logError(error.message);
}
private handleConnection = (connection: webSocket.connection) => {
    this.connection = connection;
    this.logger?.logInfo(`successfully connected to address ${this.url}`);
    this.connection.on("error", this.handleConnectionError);
    this.connection.on("close", this.handleConnectionClose);
    this.connection.on("message", this.handleConnectionMessage);
}
private handleConnectionError = (error:Error) => {
    this.logger?.logError(error.toString());
    this.status = WebsocketStatus.STOPPED;
    this.connection?.close();
}
private handleConnectionClose = () => {
    this.logger?.logInfo("connection closed");
    this.status = WebsocketStatus.STOPPED;
    this.connection?.close();
}
private handleConnectionMessage = (message: webSocket.Message) => {
    this.logger?.logInfo(message.toString());
}

方法三:事件监听时用箭头函数包裹回调

在调用on方法时,用箭头函数包裹类方法,保留类实例的this:

constructor(url: string, logger?: Logger){
    if(logger)
        this.logger = logger;
    this.url = url;
    this.status = WebsocketStatus.IDLE;
    this.client = new webSocket.client();
    this.client.on("connectFailed", (err) => this.handleConnectionFailed(err));
    this.client.on("connect", (conn) => this.handleConnection(conn));
}

同时,handleConnection内部的事件监听也要做同样处理:

private handleConnection(connection: webSocket.connection){
    this.connection = connection;
    this.logger?.logInfo(`successfully connected to address ${this.url}`);
    this.connection.on("error", (err) => this.handleConnectionError(err));
    this.connection.on("close", () => this.handleConnectionClose());
    this.connection.on("message", (msg) => this.handleConnectionMessage(msg));
}

内容的提问来源于stack exchange,提问作者Mond666

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 04:45:18