
在 tRPC 中通过 createTRPCClient 与 httpBatchLink 连接客户端并开始端到端类型安全查询【免费下载链接】trpc♀️ Move Fast and Break Nothing. End-to-end typesafe APIs made easy.项目地址: https://gitcode.com/GitHub_Trending/tr/trpc本篇指南基于 tRPC 官网首页“三步快速上手”中的第三步对应文档 www/docs/landing-intro/Step3.md在服务端路由已定义并监听 HTTP 端口之后使用createTRPCClient配合httpBatchLink创建类型安全的客户端直接以“方法调用”的方式查询后端 procedure。读完本文你将理解 tRPC 客户端如何在零代码生成的前提下获得与后端完全一致的 TypeScript 推断、httpBatchLink的批处理原理以及输入校验、类型导出与运行约束之间的完整链路。三步流程中的位置从定义 Procedure 到发起查询tRPC 官网上展示的快速上手由三个连续步骤组成其在文档站点中的代码片段由 www/src/components/QuickIntro.tsx 分别引入渲染描述文案也定义于该文件Step1.md——在服务端定义 Procedurequery/mutation/subscription并用zod做输入校验Step2.md——通过createHTTPServerstandalone adapter把路由挂到 HTTP 服务器并监听端口Step3.md——创建客户端并开始类型安全的查询。其中 Step2 的服务器监听代码是 Step3 客户端能够连通的前提。Step2 中的实现如下import { initTRPC } from trpc/server; import { createHTTPServer } from trpc/server/adapters/standalone; const t initTRPC.create(); const appRouter t.router({}); const { listen } createHTTPServer({ router: appRouter, }); // 服务器将监听在 3000 端口 listen(3000);因此在进入客户端代码前请确保后端已经运行在http://localhost:3000。tRPC 官方文档站点 www/docs/main/quickstart.mdx 对这套路由定义与服务器启动流程有更完整的展开仓库中 examples/minimal 等示例项目则提供了可实际运行的 client/server 完整骨架。回顾服务端可被客户端“复用类型”的路由Step3 客户端示例中声明了import type { AppRouter } from ./server因此需要先把服务端代码完整放出来便于理解类型从何而来该代码块与 Step3 同文件顶部共享仅作展示import { initTRPC } from trpc/server; import z from zod; const t initTRPC.create(); const appRouter t.router({ greeting: t.procedure .input(z.object({ name: z.string() })) .query((opts) { const { input } opts; return Hello ${input.name} as const; }), }); export type AppRouter typeof appRouter;这段代码值得拆解为四个要点initTRPC.create()创建 tRPC 核心实例t后续所有 router 与 procedure 构建器均由它派生这也是 tRPC 类型上下文的统一入口。t.router({ ... })把一组 procedure 组织成路由记录t.procedure.input(...)声明查询入参的校验器。这里使用 zod 的z.object({ name: z.string() })意味着客户端传入的input会被服务端严格校验为{ name: string }。.query()处理器从opts解构出已被校验并完成类型窄化的input在 Step1.md 中 TypeScript 会对input直接推断为{ name: string }返回Hello ${input.name}字符串。关键一步export type AppRouter typeof appRouter;。这里导出的是类型而非运行值客户端通过import type引入它即可获得与后端完全同步的类型信息这正是 tRPC “零代码生成zero codegen”类型安全的基础。创建客户端createTRPCClient与类型装饰代理服务端运行起来后在另一个模块或独立的前端工程中编写客户端代码。Step3 的核心示例import { createTRPCClient, httpBatchLink } from trpc/client; import type { AppRouter } from ./server; const trpc createTRPCClientAppRouter({ links: [ httpBatchLink({ url: http://localhost:3000, }), ], }); const res await trpc.greeting.query({ name: John }); // ^? const res: Hello John这段代码只有三层含义却贯穿了 tRPC 客户端的全部设计泛型注入createTRPCClientAppRouter把服务端导出的路由类型作为类型参数传入。在 packages/client/src/createTRPCClient.ts 中该函数先实例化一个TRPCUntypedClient再调用createTRPCClientProxyTRouter(client)返回一个“装饰后的代理客户端”。代理把调用转换为请求createTRPCClientProxy见 createTRPCClient.ts使用createRecursiveProxy拦截trpc.greeting.query(...)这类链式访问把路径拆成[greeting, query]再通过clientCallTypeToProcedureType把末尾的query映射为内部过程类型query最终以clientquery的形式发起真正的调用。也就是说客户端在运行期本质上是把“方法路径”拼成 RPC 请求而你看到的对象式调用语法来自 Proxy 的类型装饰——客户端方法的分派机制也定义于此文件query/mutate/subscribe分别对应三种过程类型。类型安全来自装饰类型而非代码生成TRPCClient类型与DecoratedProcedureRecord见同一文件的类型定义会递归遍历AppRouter记录对每个 procedure 推断其输入类型inferProcedureInput与输出类型inferTransformedProcedureOutput据此为每个过程挂上带签名的方法。因此trpc.greeting.query的入参必须是{ name: string }返回值被推断为字面量类型Hello John服务端用as const约束了返回值的字面量类型编辑器会给出与后端完全一致的补全与报错——类型即文档无需任何 schema 同步或代码生成步骤。httpBatchLink把多个调用批量为一次 HTTP 请求示例里使用的链接是httpBatchLink而非单个请求的httpLink。从 packages/client/src/links/httpBatchLink.ts 的源码可以看到它的批处理语义链接内部按过程类型query与mutation各自维护一个基于dataLoader位于 packages/client/src/links/internals/dataLoader.ts的批处理器。同一事件循环中发出的多个查询会先被收集起来再合并为对单个 HTTP 端点的一次请求从而减少网络往返。服务端支持一次请求携带多个操作并返回数组结果httpBatchLink对返回的数组按操作顺序一一还原见源码中resJSON.map(...)的处理逻辑。该链接提供两个可配置项用于约束批处理行为定义于 packages/client/src/links/HTTPBatchLinkOptions.ts在 httpBatchLink.ts 中消费maxURLLength默认Infinity。由于批量请求可能通过 URL 携带多个输入当拼接出的 URL 超过该长度时会自动拆分为更小的批次避免超出服务器/代理对 URL 的长度限制。maxItems默认Infinity。限制单个批次最多容纳的操作数量超过则拆分。当两者均为Infinity时跳过长度计算直接放行源码中的快速通道判断。httpBatchLink不支持subscription类型——源码在收到订阅操作时会直接抛出错误提示应改用httpSubscriptionLink或wsLink。普通查询/变更场景使用它即可获得开箱即用的批处理。除httpBatchLink外packages/client/src/links.ts 还导出httpLink、httpBatchStreamLink、loggerLink、splitLink、retryLink、wsLink等链接links数组按顺序串联因此完全可以在httpBatchLink之前插入loggerLink记录请求日志。发起类型安全的查询运行与验证当后端在http://localhost:3000监听、且客户端用上述代码连接到同一地址后执行trpc.greeting.query({ name: John })即可获得结果入参在客户端被 TypeScript 约束为{ name: string }若传入缺少字段或类型不符的对象编辑器会立即报错。该调用通过网络到达服务端后服务端会再次用 zod schema 校验真实输入形成“客户端类型约束 服务端运行时校验”的双保险。返回值res的类型被推断为Hello Johntwoslash 检查标记^?展示的正是这一推断结果。如果你修改了服务端 procedure 的输入或输出类型并重新导出AppRouter客户端无需重新生成任何代码类型错误就会在编译期暴露出来。需要注意的是import type { AppRouter } from ./server是类型导入不会把服务端代码打进客户端运行时实际项目中通常把路由类型发布到共享位置例如独立的shared包或服务端模块仅导出类型。仓库中 examples/express-minimal/src、examples/standalone-server/src 等示例以及官方文档 客户端概览 与 vanilla 客户端指南分别展示了在真实工程中组织客户端与共享类型的更多写法。小结以 Step3.md 为核心的完整链路可以概括为服务端用initTRPC定义带 zod 校验的 procedure 并导出AppRouter类型 → 用 standalone adapter 监听 3000 端口 → 客户端以createTRPCClientAppRouter注入类型、以httpBatchLink指向同一地址 → 之后便可以用类型安全的trpc.greeting.query(...)直接查询。这一过程中既没有手写 REST 端点、也没有生成客户端 SDK类型在客户端与服务端之间通过 TypeScript 的类型系统自然流通——这正是 tRPC 端到端类型安全体验最直观的落地形态。【免费下载链接】trpc♀️ Move Fast and Break Nothing. End-to-end typesafe APIs made easy.项目地址: https://gitcode.com/GitHub_Trending/tr/trpc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考