Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

error TS2345: Argument of type 'ISchoolService' is not assignable to parameter of type 'ServiceDefinition<UntypedServiceImplementation>' #144

Open
khteh opened this issue Jul 14, 2024 · 9 comments

Comments

@khteh
Copy link

khteh commented Jul 14, 2024

I generate grpc Typescript code with:

"proto": "npx grpc_tools_node_protoc --js_out=import_style=commonjs,binary:./grpc/client --grpc_out=./grpc/client --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` -I ./grpc/proto ./grpc/proto/*.proto && npx grpc_tools_node_protoc --plugin=protoc-gen-ts=`which protoc-gen-ts` --ts_out=./grpc/client -I ./grpc/proto ./grpc/proto/*.proto",

and hit the following error:

Services/SchoolService.ts:205:23 - error TS2345: Argument of type 'ISchoolService' is not assignable to parameter of type 'ServiceDefinition<UntypedServiceImplementation>'.
  Index signature for type 'string' is missing in type 'ISchoolService'.

205     server.addService(SchoolService, new ServerImpl());

Environment

  • OS name, version and architecture: [e.g. Linux Ubuntu 18.04 amd64] Ubuntu 24.04
  • Node version [e.g. 8.10.0] 22.4.1
  • Node installation method [e.g. nvm] apt
  • If applicable, compiler version [e.g. clang 3.8.0-2ubuntu4] g++ 13.2.0
  • Package name and version [e.g. [email protected]]:
    "grpc_tools_node_protoc_ts": "^5.3.3",
    "@grpc/grpc-js": "^1.10.10",

What do I miss?

@rmlakhani01
Copy link

rmlakhani01 commented Aug 18, 2024

I got a similar error when I was building mine. I was able to resolve the issue by adding the following line to the service.ts file. I've attached my code for more clarity.

server.ts

import { Server, ServerCredentials } from '@grpc/grpc-js'
import { GreeterServiceService } from './proto/greet_grpc_pb'
import { GreeterService } from './service'

const main = () => {
  const server = new Server()
  server.bindAsync(
    '0.0.0.0:50051',
    ServerCredentials.createInsecure(),
    (err: Error | null, port: number) => {
      if (err) console.error('Error caught: ' + err)

      server.addService(GreeterServiceService, new GreeterService())
      console.log(`gRPC Server listening on port ${port}`)
    },
  )
}

main()

service.ts

import { handleUnaryCall, UntypedHandleCall } from '@grpc/grpc-js'
import { IGreeterServiceServer } from './proto/greet_grpc_pb'
import { GreetRequest, GreetResponse } from './proto/greet_pb'

export class GreeterService implements IGreeterServiceServer {
  [name: string]: UntypedHandleCall \\ <---THE FIX IS HERE 
  greet: handleUnaryCall<GreetRequest, GreetResponse> = (call, callback) => {
    const request = call.request
    const response = new GreetResponse()
    response.setResult(
      'Hello, ' + request.getName() + '! Welcome to gRPC World :)',
    )
    callback(null, response)
  }
}

I hope this helps!

@khteh
Copy link
Author

khteh commented Aug 18, 2024

Doesn't help.

@rmlakhani01
Copy link

Would you mind sharing the code?

@khteh
Copy link
Author

khteh commented Aug 18, 2024

@rmlakhani01
Copy link

I can't find the file where the error occurred. Could you link it?

@khteh
Copy link
Author

khteh commented Aug 18, 2024

@rmlakhani01
Copy link

rmlakhani01 commented Aug 18, 2024

So I poked around and I think the compilation of your decorators might be part of the problem as an example this is my compiled file for my greeter service.

greet_grpc_pb.d.ts

// package: greeter
// file: greet.proto

/* tslint:disable */
/* eslint-disable */

import * as grpc from "@grpc/grpc-js";
import * as greet_pb from "./greet_pb";

interface IGreeterServiceService extends grpc.ServiceDefinition<grpc.UntypedServiceImplementation> {
    greet: IGreeterServiceService_IGreet;
}

interface IGreeterServiceService_IGreet extends grpc.MethodDefinition<greet_pb.GreetRequest, greet_pb.GreetResponse> {
    path: "/greeter.GreeterService/Greet";
    requestStream: false;
    responseStream: false;
    requestSerialize: grpc.serialize<greet_pb.GreetRequest>;
    requestDeserialize: grpc.deserialize<greet_pb.GreetRequest>;
    responseSerialize: grpc.serialize<greet_pb.GreetResponse>;
    responseDeserialize: grpc.deserialize<greet_pb.GreetResponse>;
}

export const GreeterServiceService: IGreeterServiceService;

// HERE
export interface IGreeterServiceServer extends grpc.UntypedServiceImplementation {
    greet: grpc.handleUnaryCall<greet_pb.GreetRequest, greet_pb.GreetResponse>;
}

export interface IGreeterServiceClient {
    greet(request: greet_pb.GreetRequest, callback: (error: grpc.ServiceError | null, response: greet_pb.GreetResponse) => void): grpc.ClientUnaryCall;
    greet(request: greet_pb.GreetRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: greet_pb.GreetResponse) => void): grpc.ClientUnaryCall;
    greet(request: greet_pb.GreetRequest, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: greet_pb.GreetResponse) => void): grpc.ClientUnaryCall;
}

export class GreeterServiceClient extends grpc.Client implements IGreeterServiceClient {
    constructor(address: string, credentials: grpc.ChannelCredentials, options?: Partial<grpc.ClientOptions>);
    public greet(request: greet_pb.GreetRequest, callback: (error: grpc.ServiceError | null, response: greet_pb.GreetResponse) => void): grpc.ClientUnaryCall;
    public greet(request: greet_pb.GreetRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: greet_pb.GreetResponse) => void): grpc.ClientUnaryCall;
    public greet(request: greet_pb.GreetRequest, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: greet_pb.GreetResponse) => void): grpc.ClientUnaryCall;
}

The interface that you have declare in the file is missing the inheritance of grpc.UntypedServiceImplementation

This is the commands I used to generate my files.

./scripts/gen.sh

npm install grpc_tools_node_protoc_ts --save-dev

# generate js codes via grpc-tools
grpc_tools_node_protoc \
--js_out=import_style=commonjs,binary:./proto \
--grpc_out=grpc_js:./proto \
--plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` \
-I ./proto \
./proto/*.proto

# generate d.ts codes
protoc \
--plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts \
--ts_out=grpc_js:./proto \
-I ./proto \
./proto/*.proto

Hopefully this helps :) Just an FYI I am just getting more familiar with writing TypeScript gRPC code.

@khteh
Copy link
Author

khteh commented Aug 19, 2024

Your build script seems to work but when I run the application:

$ n run start

> [email protected] start
> export NODE_ENV=development&& node build/src/webapi/server.js

file:///usr/src/Node.JSRestAPI/build/src/webapi/Services/SchoolService.js:10
import { CommonStudentsResponse } from "../grpc/client/school_pb.js";
         ^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: The requested module '../grpc/client/school_pb.js' does not provide an export named 'CommonStudentsResponse'
    at ModuleJob._instantiate (node:internal/modules/esm/module_job:171:21)
    at async ModuleJob.run (node:internal/modules/esm/module_job:254:5)
    at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:485:26)
    at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:109:5)

Node.js v22.6.0

@rmlakhani01
Copy link

rmlakhani01 commented Aug 22, 2024

you need to use a package called ts-node

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants