我试图将类型检查添加到通过Web套接字创建的api的前端。我省去了我认为与该问题无关的复杂部分,但是如果需要,我可以提供更多信息。我有一台服务器在Web套接字上侦听格式为c|endpoint|command|data
作为字符串的消息,并将使用请求的数据进行答复。该部分工作良好,但我想在客户端部分添加类型检查,以帮助调试。每个端点都有多个命令,每个端点都带有自己的自定义数据对象,该对象在发送之前已进行了字符串化,因此每个命令必须是一个函数,该函数接收套接字和数据并返回发送回的数据。
interface Socket {
send(data: string): void
}
interface Command<T> {
(socket: Socket, data: T): string | Promise<string>
}
interface Endpoints {
[index: string]: {
[index: string]: Command<any>
},
test: {
hello: Command<{testarg: string}>
}
}
此示例具有一个端点(test
)和一个命令(hello
),该命令采用结构为{testarg: string}
的数据。其他命令将具有不同的所需数据结构。
现在,我还有另一个功能可以从客户端发送命令,这是我希望进行类型检查的地方。
class ClientSocket {
// some parts not shown
socket!: WebSocket
call<T extends keyof Endpoints, K extends keyof Endpoints[T], U>(endpoint: T, command: K, data: U) {
// call the api: this.socket.send(`c|${endpoint}|${command}|${JSON.stringify(data)}`) and save the promise resolve for later resolution when we get a reply. I left that out since it's not exactly relevant.
return "promise for results of api call"
}
}
我想调用上面的三个参数,端点,命令和数据,将它们类型检查到Endpoints接口,所以如果尝试使用它,则会出现错误:call("test", "hello", {})
,因为它缺少{ {1}}属性。我想出了如何检查前两个命令,所以我调用了一个有效的命令,但是我不知道如何对数据(U)进行类型检查。
感谢您的帮助。
答案 0 :(得分:2)
您需要编写一个小的类型包装器,以获取Endpoints [T] [K]中命令的数据类型:
type CommandData<T extends keyof Endpoints, K extends keyof Endpoints[T]> = Endpoints[T][K] extends Command<infer TData> ? TData : never;
...
call<T extends keyof Endpoints, K extends keyof Endpoints[T]>(endpoint: T, command: K, data: CommandData<T, K>) {
// call the api: this.socket.send(`c|${endpoint}|${command}|${JSON.stringify(data)}`) and save the promise resolve for later resolution when we get a reply. I left that out since it's not exactly relevant.
return "promise for results of api call"
}
...
new ClientSocket().call("test", "hello", { testarg: "hello" }); // { testarg: string } is expected
但是您可以将其缩短为:
...
call<T extends keyof Endpoints, K extends keyof Endpoints[T]>(endpoint: T, command: K, data: Endpoints[T][K] extends Command<infer TData> ? TData : never) {
...
有关infer关键字的更多信息,请参见https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html。