因为不用monorepo而放弃tRPC?教你如何在前后端分开项目中使用tRPC

之前写过一篇关于tRPC的文章 还在前后端分离?来试试tRPC与Next.js吧! - 掘金 (juejin.cn),评论里有同学问在前后端分离的项目中可以使用吗,钻研了一下在前后端分开的项目中的如何使用trpc。

最简单的方式应该直接把server上传为包(没试过),然后让客户端安装就行,但是这样可能会让一些自动生成的类型的库无效比如prisma。所以还得优化一下

创建示例项目

首先先创建两个仓库的文件,client和server,执行pnpm init初始化项目,都创建一个index.ts文件

server

  1. server 安装依赖 pnpm i typescript @trpc/server zod
  2. 创建tsconfig.json文件,我们制定编译后js代码的输出路径为./dist,类型声明的输出路径为./types,strict必须设置为true。
json 复制代码
{
  "compilerOptions": {
    "composite": true,
    "strict": true,
    "outDir": "./dist",
    "declarationDir": "./types",
    "removeComments": false
  },
  "include": ["./"]
}
  1. 复制官方实例,简单写一个trpc程序
ts 复制代码
import { initTRPC } from '@trpc/server';
import { z } from 'zod';
import { createHTTPServer } from '@trpc/server/adapters/standalone';

const t = initTRPC.create();
export const router = t.router;
export const publicProcedure = t.procedure;

const appRouter = router({
  /** 这是测试!! */
  test: publicProcedure
    .input(
      z.object({
        field1: z.number(),
        field2: z.string(),
      }),
    )
    .query(async () => {
      return {
        date: new Date(),
        number: 1,
        string: 1,
        nested: {
          a: 1,
        },
        array: [],
      };
    }),
});

export type AppRouter = typeof appRouter;

const server = createHTTPServer({
  router: appRouter,
});

server.listen(3000);
  1. 然后直接运行tsc,编译整个项目。得到编译后文件types/index.d.ts文件,

client

  1. 先安装依赖pnpm install typescript @trpc/client
  2. 把server发包有点麻烦了,这里为了方便我们直接使用pnpm link ../server直接模拟安装了server的依赖(lotus-trpc-server),npm也可以直接把gihub的仓库当成依赖,不需要发包。
  1. 照着官方示例写点代码,并且AppRouter的类型从server获取
ts 复制代码
import { createTRPCProxyClient, httpBatchLink } from '@trpc/client';
import type { AppRouter } from 'lotus-trpc-server/types'; // 从后端拿到的AppRouter
type ErrorShape = AppRouter['_def']['_config']['$types']['errorShape'];

const trpc = createTRPCProxyClient<AppRouter>({
  links: [
    httpBatchLink({
      url: 'http://localhost:3000',
    }),
  ],
});

trpc.test
  .query({})
  .then((res) => {})
  .catch((err: ErrorShape) => {});
  1. 让我们来检验一下成果

可以看到catch这里我搞了个骚操作,把后端的error类型拿到了。

后端的注释文档也是正常显示的

ok,一切运行正常,非常完美!在我的另一个使用prisma的项目中也进行了测试,可以正常拿到prisma的类型。

其他

可能会有人觉得ts的类型有时候不够直观,完全看不出要传什么 可以参考一下这个类型工具,可以把ide提示的字段扩展开,更直观看到有什么字段visual studio code - How can I see the full expanded contract of a Typescript type? - Stack Overflow

ts 复制代码
export type Expand<T> = T extends (...args: infer A) => infer R
  ? (...args: Expand<A>) => Expand<R>
  : T extends infer O
  ? { [K in keyof O]: O[K] }
  : never;

export type ExpandRecursively<T> = T extends (...args: infer A) => infer R
  ? (...args: ExpandRecursively<A>) => ExpandRecursively<R>
  : T extends object
  ? T extends infer O
    ? { [K in keyof O]: ExpandRecursively<O[K]> }
    : never
  : T;

使用前:

使用后:

这下没有理由不使用tRPC了吧,都给我狠狠的用!

相关推荐
pixle01 天前
从零学习Node.js框架Koa 【七】Koa实战:构建企业级邮箱验证注册系统
javascript·学习·node.js·koa·注册·全栈·邮箱注册
用户47949283569153 天前
CVE-2025-55182:React 史上最严重漏洞,CVSS 满分 10.0
安全·react.js·全栈
Mintopia3 天前
🤖 大模型AI对话系统:消息结构展示设计猜想
人工智能·llm·全栈
Mintopia4 天前
🏗️ 系统架构之:大模型 Token 计费方案
人工智能·架构·全栈
汤姆Tom7 天前
前端转战后端:JavaScript 与 Java 对照学习指南(第四篇 —— List)
前端·编程语言·全栈
czc6668 天前
【项目实战】如何设计一个可以无限叠楼并且支持一键跳转目标的游标评论树?
全栈
Mintopia8 天前
🚀 2025全栈架构方案汇总与未来分析
人工智能·架构·全栈
我叫黑大帅9 天前
存储管理在开发中有哪些应用?
前端·后端·全栈
汤姆Tom9 天前
前端转战后端:JavaScript 与 Java 对照学习指南(第三篇 —— Map 对象)
java·javascript·全栈
HX4369 天前
Swift - Sendable (not just Sendable)
人工智能·ios·全栈