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

如何通过TypeScript装饰器实现Socket.io事件与类方法绑定

使用TypeScript装饰器简化Socket.io事件绑定

我尝试用TypeScript装饰器简化Socket.io逻辑,现有代码如下:

const Event: any = (name) => {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        console.log(target, propertyKey, descriptor);
    };
};

class ServerRoom {
    private server: Server;

    @Event("connection")
    onConnection(socket: Socket) {

    }

}

class PlayerRoom {
    private socket: Socket;

    constructor(socket: Socket) {
        this.socket = socket;
    }

    @Event("move")
    onMove(move: any) {
        console.log("Move: ", move);
    }

    @Event("disconnect")
    onDisconnect() {
        console.log("disconnected");
    }

}

我希望实现:

  • PlayerRoom实例的socket收到move、disconnect事件时,自动调用对应的onMove、onDisconnect方法
  • ServerRoom的server收到connection事件时,自动触发onConnection方法

解决方案

1. 改造Event装饰器,存储事件与方法映射

首先需要一个注册表来记录每个类的事件和对应方法的关联关系,在装饰器执行时填充这个注册表:

// 注册表:键为类原型,值为事件-方法映射数组
const eventRegistry = new Map<any, Array<{ eventName: string; methodName: string }>>();

// 类型化的Event装饰器
const Event = (eventName: string) => {
    return function (target: any, propertyKey: string) {
        let events = eventRegistry.get(target);
        if (!events) {
            events = [];
            eventRegistry.set(target, events);
        }
        // 存入当前事件与方法名的映射
        events.push({ eventName, methodName: propertyKey });
    };
};

2. 实现PlayerRoom的事件自动绑定

在PlayerRoom的构造函数中,从注册表取出事件映射,给socket绑定对应的方法(注意绑定this上下文):

class PlayerRoom {
    private socket: Socket;

    constructor(socket: Socket) {
        this.socket = socket;
        // 初始化事件绑定
        this.bindEvents();
    }

    private bindEvents() {
        const events = eventRegistry.get(PlayerRoom.prototype);
        if (!events) return;

        events.forEach(({ eventName, methodName }) => {
            // 绑定事件回调,确保方法内的this指向当前实例
            this.socket.on(eventName, (...args) => {
                (this as any)[methodName](...args);
            });
        });
    }

    @Event("move")
    onMove(move: any) {
        console.log("Move: ", move);
    }

    @Event("disconnect")
    onDisconnect() {
        console.log("disconnected");
    }
}

3. 实现ServerRoom的事件自动绑定

同理,在ServerRoom的构造函数中完成server的事件绑定:

class ServerRoom {
    private server: Server;

    constructor(server: Server) {
        this.server = server;
        // 初始化事件绑定
        this.bindEvents();
    }

    private bindEvents() {
        const events = eventRegistry.get(ServerRoom.prototype);
        if (!events) return;

        events.forEach(({ eventName, methodName }) => {
            this.server.on(eventName, (...args) => {
                (this as any)[methodName](...args);
            });
        });
    }

    @Event("connection")
    onConnection(socket: Socket) {
        // 新连接建立时创建PlayerRoom实例
        new PlayerRoom(socket);
    }
}

4. TypeScript配置要求

要启用装饰器特性,需在tsconfig.json中添加以下配置:

{
    "compilerOptions": {
        "experimentalDecorators": true,
        "target": "ES6" // 或更高版本,确保支持装饰器语法
    }
}

内容的提问来源于stack exchange,提问作者Andrea D'Attero

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 17:51:29