首页 > 解决方案 > 如何将打字稿泛型用于动态函数参数

问题描述

我正在尝试围绕节点的 gRPC bindings创建一个包装器方法。我想创建一个调用的方法,该方法调用底层类的方法,但还要对方法请求参数进行类型检查。rpcWrapperClientGrpcClient

这是我将交叉发布到TS 游乐场的示例。

type ReqA = { type: 'a' }
type ReqB = { type: 'b' }

class GrpcClient {
    findA(request: ReqA) { };
    findB(request: ReqB) { };
}

class WrapperClient {
    rpc<GrpcClient, TMethod extends keyof GrpcClient>(client: GrpcClient, method: TMethod, req: any) {
    }
}

const grpcClient = new GrpcClient()
const client = new WrapperClient()

// This works

grpcClient.findA({ type: 'a' }) // correct
grpcClient.findB({ type: 'b' }) // correct

// This doesn't.
// It Matches the method name. That's good.
// But it does not check the request type.

client.rpc(grpcClient, 'findA', 1) // should fail
client.rpc(grpcClient, 'findB', 1) // should fail
client.rpc(grpcClient, 'findC', 1) // double fail, the method check works though

我可以使用extends keyof泛型表达式对方法名称进行类型检查。我无法输入检查请求参数。

我可以将联合硬编码为请求参数类型。

    rpc<GrpcClient, TMethod extends keyof GrpcClient>(client: GrpcClient, method: TMethod, req: ReqA | ReqB) {

gRPC 绑定是动态生成的,我不想维护在重新生成绑定时可能更改的请求类型列表。

想法?

标签: node.jstypescriptgenericsgrpc

解决方案


您可以使用条件类型来确定请求类型:

type ReqA = { type: 'a' }
type ReqB = { type: 'b' }

class PeopleServiceClient {
    findA(request: ReqA) { };
    findB(request: ReqB) { };
}

class WrapperClient {
    rpc<PeopleServiceClient, TMethod extends keyof PeopleServiceClient>(
        client: PeopleServiceClient, method: TMethod,
        req: PeopleServiceClient[TMethod] extends (arg: infer T) => void ? T : never) {
    }
}

const grpcClient = new PeopleServiceClient()
const client = new WrapperClient()

grpcClient.findA({ type: 'a' }) // correct
grpcClient.findB({ type: 'b' }) // correct

client.rpc(grpcClient, 'findA', {type: 'a'}) // correct
client.rpc(grpcClient, 'findA', {type: 'b'}) // fails
client.rpc(grpcClient, 'findA', 1) // fails
client.rpc(grpcClient, 'findB', 1) // fails
client.rpc(grpcClient, 'findC', 1) // fails

推荐阅读