TypeScript gRPC服务器开发报错排查:类型不匹配与属性可选性问题
我来帮你拆解每个错误的原因,再给出具体的修复方案:
错误1:GetAllNews服务提示“与类型'NewsList'无共同属性”
原因:你的Proto文件定义GetAllNews的返回值是NewsList类型,这个类型是一个包含repeated News news字段的对象,但你直接返回了newsLists数组,和NewsList的结构完全不匹配,所以TypeScript会报错。
修复:把返回值包装成符合NewsList结构的对象:
"GetAllNews": (_, callback) => { callback(null, { news: newsLists }) },
错误2:AddNews服务无法向数组添加元素
原因:你的newsLists数组里的元素是所有字段都必填的News类型,但gRPC生成的TS类型中,call.request的字段是可选的(客户端可能没传全字段),所以合并后的news对象会带有可选字段,无法直接赋值给必填的News类型。
修复:先检查客户端传入的必填字段是否存在,再做类型断言确保符合News类型:
"AddNews": (call, callback) => { // 校验必填字段是否存在 if (!call.request.title || !call.request.body || !call.request.postImage) { callback({ code: grpc.status.INVALID_ARGUMENT, message: "title、body、postImage为必填字段" }, null) return } let news = { id: uuidv4(), ...call.request} as News newsLists.push(news) callback(null, news) },
同时记得导入News类型:
import { NewsServiceHandlers, News } from './proto/newsPackage/NewsService';
错误3:EditNews服务出现“Type 'string | undefined' is not assignable to type 'string'”
原因:call.request的字段是可选类型(string | undefined),但newsItem的字段是必填的string类型,直接赋值会触发类型不匹配;另外你还没处理newsItem可能为undefined的情况(找不到对应ID的新闻时)。
修复:先检查新闻是否存在,再选择性更新存在的字段:
"EditNews": (call, callback) => { const newsId = call.request.id const newsItem = newsLists.find(({ id }) => newsId === id) if (!newsItem) { callback({ code: grpc.status.NOT_FOUND, message: "未找到对应新闻" }, null) return } // 只更新客户端传入的非undefined字段 if (call.request.title !== undefined) { newsItem.title = call.request.title } if (call.request.body !== undefined) { newsItem.body = call.request.body } if (call.request.postImage !== undefined) { newsItem.postImage = call.request.postImage } callback(null, newsItem) },
额外的逻辑错误(GetNews)
你在GetNews里写的判断条件是id !== newsId,这会返回第一个ID不等于传入值的新闻,逻辑完全反了,需要修正为:
"GetNews": (call, callback) => { const newsId = call.request.id const newsItem = newsLists.find(({ id }) => id === newsId) if (!newsItem) { callback({ code: grpc.status.NOT_FOUND, message: "未找到对应新闻" }, null) return } callback(null, newsItem) },
完整修复后的server.ts代码
import path from 'path' import * as grpc from '@grpc/grpc-js' import * as protoLoader from '@grpc/proto-loader' import { v4 as uuidv4 } from 'uuid' import { ProtoGrpcType } from './proto/news'; import { NewsServiceHandlers, News } from './proto/newsPackage/NewsService'; const PORT = 9999; const PROTO_FILE = './proto/random.proto' const packageDef = protoLoader.loadSync(path.resolve(__dirname, PROTO_FILE)) const grpcObj = (grpc.loadPackageDefinition(packageDef) as unknown) as ProtoGrpcType const newsPackage = grpcObj.newsPackage let newsLists: News[] = [ { id: "1", title: "Note 1", body: "Content 1", postImage: "Post image 1" }, { id: "2", title: "Note 2", body: "Content 2", postImage: "Post image 2" }, ] function main() { const server = getServer() server.bindAsync(`0.0.0.0:${PORT}`, grpc.ServerCredentials.createInsecure(), (err, port) => { if (err) { console.error(err) return } console.log('Your server is started on port', port) server.start() }) } function getServer() { const server = new grpc.Server() server.addService(newsPackage.NewsService.service, { "GetAllNews": (_, callback) => { callback(null, { news: newsLists }) }, "GetNews": (call, callback) => { const newsId = call.request.id const newsItem = newsLists.find(({ id }) => id === newsId) if (!newsItem) { callback({ code: grpc.status.NOT_FOUND, message: "未找到对应新闻" }, null) return } callback(null, newsItem) }, "AddNews": (call, callback) => { if (!call.request.title || !call.request.body || !call.request.postImage) { callback({ code: grpc.status.INVALID_ARGUMENT, message: "title、body、postImage为必填字段" }, null) return } let news = { id: uuidv4(), ...call.request} as News newsLists.push(news) callback(null, news) }, "EditNews": (call, callback) => { const newsId = call.request.id const newsItem = newsLists.find(({ id }) => newsId === id) if (!newsItem) { callback({ code: grpc.status.NOT_FOUND, message: "未找到对应新闻" }, null) return } if (call.request.title !== undefined) { newsItem.title = call.request.title } if (call.request.body !== undefined) { newsItem.body = call.request.body } if (call.request.postImage !== undefined) { newsItem.postImage = call.request.postImage } callback(null, newsItem) }, "DeleteNews": (call, callback) => { const newsId = call.request.id; newsLists = newsLists.filter(({ id }) => id !== newsId); callback(null, {}); } } as NewsServiceHandlers) return server } main()
内容的提问来源于stack exchange,提问作者ferryawijayanto
相关产品推荐
相关产品推荐

