如何强制打字稿将参数解释为名称空间而不是 class,当它们具有相同的名称时 - gRPC

How to force typescript to interpret a parameter as a namespace rather than a class, when they have the same name - gRPC

抱歉标题太长...

我正在使用 gRPC 和 typescript 实现一个简单的 crud 小系统,我的问题是:自动生成的文件为我的 protoFile 中的每个参数创建一个 class 和一个类型,例如: UserId 参数生成带有 getUserId 等的 class,以及类型为 UserId 的命名空间。

问题是,当我尝试在 client 中使用该方法时,打字稿需要 class 作为参数,而不是类型。

所以而不是 getUsersById({id: 1}, callback)... 它要求我做 getUsersById(new UserId)

user.Proto:

syntax = "proto3";

package userServicePKG;

message User {
    int32 id = 1;
    string name = 2;
    int32 age = 3;
}

message UserId {
    int32 id = 1;
}

service UserService{
    rpc getUserById (UserId) returns (User);
}

UserServiceClientPb.ts(生成 Protobuf)- 函数定义

methodInfogetUserById = new grpcWeb.AbstractClientBase.MethodInfo(
    User,
    (request: UserId) => {
      return request.serializeBinary();
    },
    User.deserializeBinary
  );

  getUserById(
    request: UserId,
    metadata: grpcWeb.Metadata | null): Promise<User>;

  getUserById(
    request: UserId,
    metadata: grpcWeb.Metadata | null,
    callback: (err: grpcWeb.Error,
               response: User) => void): grpcWeb.ClientReadableStream<User>;

  getUserById(
    request: UserId,
    metadata: grpcWeb.Metadata | null,
    callback?: (err: grpcWeb.Error,
               response: User) => void) {
    if (callback !== undefined) {
      return this.client_.rpcCall(
        new URL('/userServicePKG.UserService/getUserById', this.hostname_).toString(),
        request,
        metadata || {},
        this.methodInfogetUserById,
        callback);
    }
    return this.client_.unaryCall(
    this.hostname_ +
      '/userServicePKG.UserService/getUserById',
    request,
    metadata || {},
    this.methodInfogetUserById);
  }

user_pb.d.ts(Protobuf 生成)- 定义类型和 classes:

export class UserId extends jspb.Message {
  getId(): number;
  setId(value: number): UserId;

  serializeBinary(): Uint8Array;
  toObject(includeInstance?: boolean): UserId.AsObject;
  static toObject(includeInstance: boolean, msg: UserId): UserId.AsObject;
  static serializeBinaryToWriter(message: UserId, writer: jspb.BinaryWriter): void;
  static deserializeBinary(bytes: Uint8Array): UserId;
  static deserializeBinaryFromReader(message: UserId, reader: jspb.BinaryReader): UserId;
}

export namespace UserId {
  export type AsObject = {
    id: number,
  }
}

Client.Vue:

const client = new UserServiceClient('http://localhost:5001', null, null);

let userId = { id:1 };
client.getUserById(userId, function (error: grpcWeb.Error, response: any) {
     //do something
});

参数 userId 引发以下错误:

Argument of type '{ id: number; }' is not assignable to parameter of type 'UserId'. Type '{ id: number; }' is missing the following properties from type 'UserId': getId, setId, serializeBinary, toObject, and 8 more.Vetur(2345)

在我看来,typescript 推断 getUserById 第一个参数是 Class UserId 类型,而不是来自 命名空间 UserId.

有什么我可以做的吗?由于它是自动生成的,我觉得它应该正确解释?我在搞砸其他事情吗?我是 gRPC 的新手,所以我可能做错了什么。

提前致谢!

消息 UserId 生成为 JavaScript class。您必须提供此 class 的一个实例,实际上没有其他选择,至少对于 protoc-gen-grpc-web 生成的代码而言没有。

有一些基于 TypeScript 的替代代码生成器不需要您使用 classes。 ts-proto 和 protobuf-ts 使用简单的接口而不是 classes 来表示消息。 (我是protobuf-ts的作者)

例如,protobuf-ts 从您的 user.proto 生成代码,可以像这样使用:

// gRPC-web provided by @protobuf-ts/grpcweb-transport
const transport = new GrpcWebFetchTransport("http://localhost:5001");

const client = new UserServiceClient(transport);

const {response} = await client.getUserById({id: 123});

console.log(
    response.id,
    response.name,
    response.age
);

我想 ts-proto 前段时间也得到了 grpc-web 的支持。也许试一试,看看您是否更喜欢生成的代码。