0

I generated a simple demo project using gRPC's but I am not able to use the generated setters. If I access the varables directly from the response I get a warning that reads. res.data.title

TS2339: Property 'title' does not exist on type 'TodoResponse'.

However res.data.title will render correctly in the browser.

I generated the gRPC code two different ways with no avail. I thought maybe the plugin was the issue.

grpc_tools_node_protoc. Example of the command used to generate the files.

# JavaScript code generation
cd view && yarn run grpc_tools_node_protoc \
    --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts \
    --ts_out=grpc_js:${PROTO_DEST} \
    --js_out=import_style=commonjs:${PROTO_DEST} \
    --grpc_out=grpc_js:${PROTO_DEST} \
    -I ${PROJ_PATH}/proto \
    ${PROJ_PATH}/proto/*.proto

Second approach.

protoc -I ${PROJ_PATH}/proto api.proto \
  --js_out=import_style=commonjs,binary:${PROJ_PATH}/view/${PROTO_DEST} \
  --plugin=protoc-gen-grpc-web=${PROJ_PATH}/view/node_modules/.bin/protoc-gen-grpc-web \
  --grpc-web_out=import_style=typescript,mode=grpcweb:${PROJ_PATH}/view/${PROTO_DEST}

The files work fine, and I can render everything that I need. I just have these annoying errors all over which will cause the linter to fail. I should be able to use the TS getters but I cannot.

example:

If I use the getter with () I get. res.data.getTodoList()

errorTypeError: res.data.getTodoList() is not a function

Without the ()

res.data.getTodoList undefined

This is what I see in my IDE. Will still compile but render the values as long as I am not using a getter.

enter image description here

Why is this happening? When we declare a variable without specifying the type, it causes the TypeScript Compiler to infer its type for you. However, this is generated code that I thought was suppose to work with grpc-web.

TodoAllResponse

 export class TodoAllResponse extends jspb.Message { 
    clearTodoList(): void;
    getTodoList(): Array<Todo>;
    setTodoList(value: Array<Todo>): TodoAllResponse;
    addTodo(value?: Todo, index?: number): Todo;

    serializeBinary(): Uint8Array;
    toObject(includeInstance?: boolean): TodoAllResponse.AsObject;
    static toObject(includeInstance: boolean, msg: TodoAllResponse): TodoAllResponse.AsObject;
    static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
    static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
    static serializeBinaryToWriter(message: TodoAllResponse, writer: jspb.BinaryWriter): void;
    static deserializeBinary(bytes: Uint8Array): TodoAllResponse;
    static deserializeBinaryFromReader(message: TodoAllResponse, reader: jspb.BinaryReader): TodoAllResponse;
}

I am not sure if I am missing a proto file command. At this point I am rather stumped

method

 async getAllTodos() {
        try {
            return await grpcClient.get<TodoAllResponse>(`/v1/getAll?${qs.stringify({

            })}`).then(res => {
                console.log("res in getAll", res.data.getTodoList) <--- undefined
                return res.data
            })
        } catch (err) {
            console.log("error" + err);
        }
    },

gRPC file

service ApiService {

    rpc GetAll(TodoRequest) returns (TodoAllResponse){
        option (google.api.http) = {
            get: "/v1/getAll"
        };
    }

}

message TodoRequest {
    string id = 1;
}


message Todo {
    string id = 1;
    string title = 2;
    string time = 3;
}

message TodoAllResponse {
    repeated Todo todo = 1;
}

Advice?

--- update ---

I was able to get it to work by creating a custom TS object.

import { ITodo } from "./Todo";

export interface ITodoAllResponse {
    todo: ITodo[];
}

--

export interface ITodo {
    id: string;
    title: string;
}

then the axios call

async getAllTodos() {
    try {
        return await grpcClient.get<ITodoAllResponse>(`/v1/getAll?${qs.stringify({
        })}`).then(res => {
            return res.data.todo
        })
    } catch (err) {
        console.log("error" + err);
    }
},

and in my component

const todoArr = ref<ITodo[]>()

However I really want to use the generated gRPC typescript models. It appears there might be an issue with repeated Todo todo = 1; but I am not completely sure.

Mike3355
  • 11,305
  • 24
  • 96
  • 184
  • 2
    The getters and setters are the way you are supposed to interact with these objects. What do you mean when you say that they "don't work"? – murgatroid99 Jan 09 '23 at 23:40
  • 1
    @murgatroid99 I updated the question. I am able to access the getters and setters but then I get an error saying it is not a function. I cannot set them manually because accessing the response values via `response.todo.title` gives me the `TS2339` warning. – Mike3355 Jan 10 '23 at 06:26
  • 2
    You say that the error is `response.getTodoList is not a function`, but the generated TS code you show doesn't have a `getTodoList ` method so I would not expect that to work. In the code with the field access errors you are trying to access the fields `title` and `id`. Those should correspond to the `getTitle` and `getId` methods, so do those work? – murgatroid99 Jan 10 '23 at 06:29
  • 1
    @murgatroid99 just woke up. The method is there and no getter or setter works. All result in the same error but they are there. https://github.com/improbable-eng/ts-protoc-gen/issues/239. I will post the `TodoAllResponse` in a moment. – Mike3355 Jan 10 '23 at 06:35
  • 1
    That issue is just mistaken. The documentation it links to is for a different code generator, which doesn't work with grpc-web anyway. Have you looked at your generated JavaScript code, to see what methods or fields are available? – murgatroid99 Jan 10 '23 at 06:38
  • @murgatroid99 maybe it is the plugin. Of course I checked the files. – Mike3355 Jan 10 '23 at 07:13
  • @murgatroid99 here are the files https://github.com/drewjocham/demo-todo-list/tree/main/view/src/proto – Mike3355 Jan 10 '23 at 07:27
  • In your first code snippet, you are trying to access fields of `res.data`, which doesn't work because you need to use getters. In the second code snippet, you are trying to access a getter directly on the `response` object. Have you tried `response.data.getTodoList()` instead? – murgatroid99 Jan 10 '23 at 07:35
  • @murgatroid99 all getters to include `response.data.getTodoList()` do not work.. `res in getAll undefined` from `console.log("res in getAll", res.data.getTodoList)`.. Removing the `()` is undefined, whereas adding `()` results in `errorTypeError: res.data.getTodoList is not a function` – Mike3355 Jan 10 '23 at 07:40
  • Your code says `response` but the error says `res`. Why? – murgatroid99 Jan 10 '23 at 07:46
  • @murgatroid99 please see the post again. – Mike3355 Jan 10 '23 at 13:38
  • @murgatroid99 it looks like it could be an issue with the proto file. I only seem to have this issue when there is an `repeated Todo todo = 1;`. When the TS and JS files are created my IDE says `res.data.todo` is not defined but it will render, just create linter issues. I make a custom TS object for it and everything is fine. It is how it is generating the array, just not sure why. – Mike3355 Jan 14 '23 at 07:13

0 Answers0