triggerUncaughtException - 转换失败并出现 1 个错误:错误:必须初始化常量“UserServiceService”

问题描述 投票:0回答:1

我正在使用 Node.js 和 TypeScript 实现 gRPC 服务器。我使用静态 gRPC 方法生成了 TypeScript 类型(

@grpc/grpc-js
grpc-tools
grpc_tools_node_protoc_ts
@types/node
@types/google-protobuf
)。但是,当尝试运行我的服务器时,我收到以下错误:

> tsx server/server.ts       
>
> node:internal/modules/run_main:122
>    triggerUncaughtException(     
>    ^
> Error [TransformError]: Transform failed with 1 error:
> C:\Dev\Nodejs-ts-gRPC\src\gen\users_grpc_pb.d.ts:24:13: ERROR: The constant 
> "UserServiceService" must be initialized
>
> // rest of the error

我的依赖项可能存在问题,因为我正在尝试使用 ESModules 实现此实现:

tsconfig.json

{
  "compilerOptions": {
    "target": "ES2017",
    "module": "ESNext",
    "moduleResolution": "node",
    "sourceMap": true,
    "rootDir": "./src",
    "outDir": "./dist",
    "strict": true,
    "allowSyntheticDefaultImports": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": false
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

package.json

{
  "name": "nodejs-ts-grpc",
  "version": "1.0.0",
  "main": "index.js",
  "type": "module",
  "scripts": {
    "build": "tsc",
    "start": "tsx src/index.ts",
    "dev": "tsx watch src/index.ts",
    "lint": "eslint \"src/**/*.{ts,js}\"",
    "lint:fix": "eslint \"src/**/*.{ts,js}\" --fix",
    "format": "prettier --write \"src/**/*.{ts,js}\"",
    "format:check": "prettier --check \"src/**/*.{ts,js}\"",
    "server": "tsx server/server.ts",
    "client": "tsx server/client.ts",
    "generate:proto": "bash proto/build.sh"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": "",
  "devDependencies": {
    "@eslint/js": "^9.16.0",
    "@types/google-protobuf": "^3.15.12",
    "@types/node": "^22.10.1",
    "@typescript-eslint/eslint-plugin": "^8.17.0",
    "@typescript-eslint/parser": "^8.17.0",
    "eslint": "^9.16.0",
    "eslint-config-prettier": "^9.1.0",
    "eslint-plugin-prettier": "^5.2.1",
    "globals": "^15.13.0",
    "grpc_tools_node_protoc_ts": "^5.3.3",
    "prettier": "^3.4.2",
    "tsx": "^4.19.2",
    "typescript": "^5.7.2",
    "typescript-eslint": "^8.17.0"
  },
  "dependencies": {
    "@grpc/grpc-js": "^1.12.2",
    "grpc-tools": "^1.12.4"
  }
}

此外,这是我生成的

users_grpc_pb.d.ts
文件:

// package: user
// file: users.proto

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

import * as grpc from '@grpc/grpc-js';
import * as users_pb from './users_pb';

interface IUserServiceService extends grpc.ServiceDefinition<grpc.UntypedServiceImplementation> {
  getUser: IUserServiceService_IGetUser;
}

interface IUserServiceService_IGetUser extends grpc.MethodDefinition<users_pb.GetUserRequest, users_pb.GetUserResponse> {
  path: '/user.UserService/GetUser';
  requestStream: false;
  responseStream: false;
  requestSerialize: grpc.serialize<users_pb.GetUserRequest>;
  requestDeserialize: grpc.deserialize<users_pb.GetUserRequest>;
  responseSerialize: grpc.serialize<users_pb.GetUserResponse>;
  responseDeserialize: grpc.deserialize<users_pb.GetUserResponse>;
}

export const UserServiceService: IUserServiceService;

export interface IUserServiceServer extends grpc.UntypedServiceImplementation {
  getUser: grpc.handleUnaryCall<users_pb.GetUserRequest, users_pb.GetUserResponse>;
}

export interface IUserServiceClient {
  getUser(request: users_pb.GetUserRequest, callback: (error: grpc.ServiceError | null, response: users_pb.GetUserResponse) => void): grpc.ClientUnaryCall;
  getUser(request: users_pb.GetUserRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: users_pb.GetUserResponse) => void): grpc.ClientUnaryCall;
  getUser(
    request: users_pb.GetUserRequest,
    metadata: grpc.Metadata,
    options: Partial<grpc.CallOptions>,
    callback: (error: grpc.ServiceError | null, response: users_pb.GetUserResponse) => void,
  ): grpc.ClientUnaryCall;
}

export class UserServiceClient extends grpc.Client implements IUserServiceClient {
  constructor(address: string, credentials: grpc.ChannelCredentials, options?: Partial<grpc.ClientOptions>);
  public getUser(request: users_pb.GetUserRequest, callback: (error: grpc.ServiceError | null, response: users_pb.GetUserResponse) => void): grpc.ClientUnaryCall;
  public getUser(request: users_pb.GetUserRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: users_pb.GetUserResponse) => void): grpc.ClientUnaryCall;
  public getUser(
    request: users_pb.GetUserRequest,
    metadata: grpc.Metadata,
    options: Partial<grpc.CallOptions>,
    callback: (error: grpc.ServiceError | null, response: users_pb.GetUserResponse) => void,
  ): grpc.ClientUnaryCall;
}

server.ts

import * as grpc from '@grpc/grpc-js';
import { UserService } from './services.ts';
import { UserServiceService } from '../src/gen/users_grpc_pb.d';

const server = new grpc.Server();

server.addService(UserServiceService, UserService);

const PORT = '50051';
server.bindAsync(`0.0.0.0:${PORT}`, grpc.ServerCredentials.createInsecure(), (err, port) => {
  if (err) {
    console.error(`Error al iniciar el servidor: ${err}`);
    return;
  }
  console.log(`Servidor gRPC escuchando en puerto ${port}`);
  server.start();
});

我用来从 .proto 文件生成 JS 和 TS 代码的脚本是:

build.sh

 #!/bin/bash

 OUT_DIR=./src/gen

 mkdir -p ${OUT_DIR}

 grpc_tools_node_protoc \
   --js_out=import_style=commonjs,binary:${OUT_DIR} \
   --grpc_out=grpc_js:${OUT_DIR} \
   --plugin=protoc-gengrpc=./node_modules/.bin/grpc_tools_node_protoc_plugin \
   -I ./proto \
   proto/*.proto

 grpc_tools_node_protoc \
   --plugin=protoc-gents=./node_modules/.bin/protoc-gen-ts \
   --ts_out=grpc_js:${OUT_DIR} \
   -I ./proto \
   proto/*.proto

知道发生了什么吗?

node.js typescript grpc es6-modules grpc-node
1个回答
0
投票

认为错误出在你的

server.ts
模块中:

import { UserServiceService } from '../src/gen/users_grpc_pb.d';

您正在尝试从类型声明文件导入常量。然而,

.d.ts
模块是用来装饰JS文件的。您不应该直接引用它们。相反,将导入更改为:

import { UserServiceService } from '../src/gen/users_grpc_pb'; // drop the ".d"

这将允许 TypeScript 编译器使用

.d.ts
进行类型检查,同时确保(可能的)JS 文件在运行时使用。

© www.soinside.com 2019 - 2024. All rights reserved.