Basically, I want to provide a wrapper function for all the RPC calls I am making. This is so that I can log specific information about each RPC call without the use of a middleware. I want to be able to get the parameter of the method which is called by doing rpc[serviceName][method] using TypeScript.
This is my current implementation where the params is not specific enough:
async rpcWrapper<Service extends keyof IRpc>(
serviceName: Service,
method: keyof IRpc[Service],
params: Object,
) {
return rpc[serviceName][method]({ ...params });
}
I have also tried to do this but have gotten an error:
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
interface IRpc {
ExampleService: ExampleService;
ExampleService2: ExampleService2;
ExampleService3: ExampleService3;
}
type of an 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;
}
What I want
rpcWrapper("ExampleService", "Login", { })
// Autocomplete tells me that I can fill in username and email
The correct type inference is sometimes hard to accomplish. In your function the
Methodtype is just the key of one method of a service and you can't access the parameters of aPropertyKey. E.g.Parameters<"Login">To get the right Method of your service you have to access this method like this
IRPc[Service][Method] //<- but this will result in unknownTherefore you have to check somehow yourIRPc[Service][Method]is a valid Function. You can do that by writing a utility type that checks if the provided generic extends any Functiontype CastFn<T> = T extends AnyFn ? T : neverNow you can access the parameters of your method like thisParameters<CastFn<IRPc[Service][Method]>>.