如何用TypeScript创建可推断RPC方法参数的泛型包装函数?
实现带类型提示的RPC调用包装函数
我想给所有RPC调用做一个包装函数,不用中间件就能记录每个RPC调用的特定信息。同时希望通过TypeScript实现,调用rpcWrapper(serviceName, method, params)时,能自动获取对应方法的参数类型,支持自动补全。
当前实现的问题
目前的params类型太宽泛,没有具体的类型提示:
async rpcWrapper<Service extends keyof IRpc>( serviceName: Service, method: keyof IRpc[Service], params: Object, ) { return rpc[serviceName][method]({ ...params }); }
尝试过的错误实现
我尝试了以下写法,但出现类型错误:
async rpcWrapper<Service extends keyof IRpc, Method extends keyof IRpc[Service]>( serviceName: Service, method: Method, params: Parameters<Method>, // 错误:Type 'Method' does not satisfy the constraint '(...args: any) => any'. ) { return rpc[serviceName][method]({ ...params }); }
相关类型定义
IRpc接口
interface IRpc { ExampleService: ExampleService; ExampleService2: ExampleService2; ExampleService3: ExampleService3; }
ExampleService类型
export declare class ExampleService { public Login(req: LoginReq): Promise<LoginResp>; public Login(ctx: ClientInvokeOptions, req: LoginReq): Promise<LoginResp>; public Logout(req: LogoutReq): Promise<CommonResp>; public Logout(ctx: ClientInvokeOptions, req: LogoutReq): Promise<CommonResp>; } export interface LoginReq { username: string; email: string; }
期望效果
调用包装函数时,参数能自动补全对应字段:
rpcWrapper("ExampleService", "Login", { }) // 自动提示可以填入username和email
解决方案
方案1:支持重载方法的参数传递
如果需要兼容带ctx和不带ctx的两种调用方式,可以直接传递原方法的所有参数,同时保留类型提示:
async function rpcWrapper< Service extends keyof IRpc, Method extends keyof IRpc[Service] >( serviceName: Service, method: Method, ...params: Parameters<IRpc[Service][Method]> ): Promise<ReturnType<IRpc[Service][Method]>> { // 这里添加日志记录逻辑 console.log(`[RPC调用] ${serviceName}.${method}`, params); return rpc[serviceName][method](...params); }
方案2:仅传递业务参数(忽略ctx)
如果希望包装函数只接收业务参数(自动省略ctx),可以通过条件类型提取方法的业务参数类型:
// 自定义类型:从重载方法中提取业务请求参数的类型 type ExtractRpcReq<T> = T extends { (req: infer R): Promise<any>; (ctx: any, req: infer R): Promise<any>; } ? R : never; async function rpcWrapper< Service extends keyof IRpc, Method extends keyof IRpc[Service] >( serviceName: Service, method: Method, params: ExtractRpcReq<IRpc[Service][Method]> ): Promise<ReturnType<IRpc[Service][Method]>> { // 日志记录 console.log(`[RPC调用] ${serviceName}.${method}`, params); // 调用不带ctx的版本 return rpc[serviceName][method](params); }
这样调用rpcWrapper("ExampleService", "Login", {})时,编辑器会自动提示username和email字段,完全符合期望效果。
内容的提问来源于stack exchange,提问作者たちぼく
相关产品推荐
相关产品推荐

