网站搜索

typescript - 在服务器和客户端上对事件进行类型定义


我有一些第三方框架,它具备在服务器上添加事件监听器并从客户端调用该事件的功能。

看起来像这样用于服务器:

framework.addEvent('myEvent1', (clientId, myParam1, myParam2...) => { my server work here })

在客户端:

let result = await framework.callRemote('myEvent1', myParam1, myParam2,...)

我不明白如何正确且方便地描述我的事件类型、它们的字符串名称以及可以在服务器和客户端使用的相关回调类型(通过从全局模块导入这些类型)。

服务器端的每个回调总是以 clientId 作为第一个参数,但接下来我的参数及其类型可能因每个事件而不同。

我只能想出这个:

export namespace ServerEvent {

    export enum Name {            
        MyEvent1 = 'MyEvent1',
        MyEvent2 = 'MyEvent2',
        MyEvent3 = 'MyEvent3',           
    }

    export namespace Func {            
        export type MyEvent1 = (myArg1: string) => void            
        export type MyEvent2 = (myArg1: number, myArg2?: boolean) => void            
        export type MyEvent3 = () => void
    }    
}

但即便如此,我也不明白如何使用它来查看服务器端和客户端的所有参数及其类型。

我找到了一些可能解决我问题的例子,但我无法理解它,也不知道如何朝这个方向推进:

const wrapper = <U extends (...args: any[]) => any>(func: U) => (...args: Parameters<U>) : ReturnType<U> => func(...args);

答案#1

我找到了一些解决方案,我怀疑不是最好的,但我几乎达到了我的目标:

// GLOBAL Module

export enum ServerEventName {
    Event1 = 'MyEvent1',
    Event2 = 'MyEvent2',
    Event3 = 'MyEvent3',
    Event4 = 'MyEvent4', // events can be withot callback type if they has no other arguments besides clientId
}

export namespace ServerCallback {
    export type Event1Callback = (arg1: string) => void
    export type Event2Callback = (arg1: number, arg2?: boolean) => void
    export type Event3Callback = () => void
}

// SERVER

function addEvent<U extends (...args: any[]) => any>(name: string, callback: (clientId: number, ...args: Parameters<U>) => ReturnType<U>) {
    someFramework.addEvent(name, (clientId: number, ...args: Parameters<U>) => { callback(clientId, ...args) })
}

addEvent<ServerCallback.Event1Callback>(ServerEventName.Event1, (clientId, arg1) => {
    console.log(clientId, arg1)
})
addEvent<ServerCallback.Event2Callback>(ServerEventName.Event2, (clientId, arg1, arg2) => {
    console.log(clientId, arg1, arg2)
})
addEvent<ServerCallback.Event3Callback>(ServerEventName.Event3, (clientId) => {
    console.log(clientId)
})


// CLIENT 

function callRemoteEvent<U extends (...args: any[]) => any>(name: string, ...args: Parameters<U>) {
    someFramework.callRemote(name, ...args)
}

callRemoteEvent<ServerCallback.Event1Callback>(ServerEventName.Event1, 'this is string')
callRemoteEvent<ServerCallback.Event2Callback>(ServerEventName.Event2, 123, true)
callRemoteEvent<ServerCallback.Event3Callback>(ServerEventName.Event3)
callRemoteEvent(ServerEventName.Event4)

IDE 语法助手成功识别类型并检查它们。

然而,也有一些缺点。事件名称枚举与它们的回调类型无关,需要正确地一起指示它们。

更新:这个答案完全解决了我的问题。