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

如何用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,提问作者たちぼく

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 13:55:37