如何将Typescript泛型用于动态函数参数

时间:2018-08-21 05:32:58

标签: node.js typescript generics grpc

我正在尝试围绕node's gRPC bindings创建一个 wrapper 方法。我想在rpc上创建一个称为WrapperClient的方法,该方法调用基础GrpcClient类上的方法,但还要键入方法和< strong>请求参数。

以下是我将交叉发布到TS playground的示例。

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绑定是动态生成的,我不希望维护一个在重新生成绑定时可能会更改的可能请求类型的列表。

有想法吗?

1 个答案:

答案 0 :(得分:1)

您可以使用conditional type来确定请求类型:

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