T3 Stack全栈实战:端到端类型安全工程t3code深度解析

发布时间:2026/10/26 16:46:36
T3 Stack全栈实战:端到端类型安全工程t3code深度解析 干我们这行的每天都被新框架、新名词轮番轰炸但有些技术组合你在看到它的第一眼就能感觉到“这次不一样”。t3code这个项目是我在去年下半年正式立项的一个全栈工程实践核心思路就八个字端到端类型安全全员 TypeScript。整套技术栈选的是现在圈内讨论度很高的 T3 Stack——Next.js 做应用框架TypeScript 打底Tailwind CSS 负责样式tRPC 接替传统 REST API 的角色再用 Prisma 统一管数据库模型。如果你正打算从“前后端分离、接口文档对接、联调半天”的老路里跳出来或者想在中小型项目里把后端和前端的协作成本砍掉一截这个项目肯定值得你花几分钟看看。它不是学院派理论堆出来的 demo而是我踩了将近一个月的坑、在真实业务页面上跑通之后沉淀下来的实操经验。下面我会把选型逻辑、初始化过程、核心链路搭建以及那些文档里不会写的排查技巧全部拆开讲清楚。1. 项目整体画像为什么说T3是一套“端到端类型安全”的解法1.1 先聊清楚 t3code 到底想解决什么问题很多业务项目在做到中后期最大的痛点其实不在功能多难写而在于前后端之间的“翻译损耗”。后端写了个接口返回字段命名不规范前端拿到的数据和联调文档对不上页面一渲染就报错改了个参数类型前端没人知道运行时才发现请求挂了。这类问题多了以后团队的时间大量花在“对齐预期”上而不是花在业务本身。t3code立项的时候我给自己定了一个非常硬性的目标从数据库表结构到 API 调用再到页面渲染中间经过的每一层数据类型都必须由编译器兜底。也就是说后端模型一旦改了前端编辑器里立刻就能看到红色波浪线而不是等浏览器控制台报错。这个目标单靠某一种技术做不到必须是一套互相咬合的组合拳这就是 T3 技术栈存在的意义。T3 这个名字来自社区里非常活跃的开发者 Theo他在自己的实践中总结出一套“简单、可维护、类型安全”的全栈方案核心成员是 Next.js、TypeScript、Tailwind CSS、tRPC另外一般还会带上 Prisma。这套组合不是为了炫技而是把“类型安全”从单一语言层面提升到了**跨层跨前后端**的层面。1.2 四个核心成员各自的角色定位先分别说下每个成员在这个体系里干的事以及我为什么把它们拼在一起。Next.js 负责“壳”和“路由”。它同时承担页面渲染、API路由、服务端组件等职责而且对 TypeScript 支持是原生级别的。在 T3 体系里Next.js 不只是个 React 框架它还是连接前端页面和后端逻辑的黏合剂。选择 App Router 还是 Pages Router 会直接影响后续代码组织方式这一点我在 2.3 节里会详细对比。TypeScript 是贯穿全场的“类型契约”。在前端它约束组件 props 和状态在服务端它约束请求入参和返回出参。真正让它发挥威力的是它作为“参数”被传递到 tRPC 和 Prisma 的泛型里让类型检查可以跨越进程边界。Tailwind CSS 负责“界面表达”。它可能乍一看跟“类型安全”没啥关系但它的核心价值其实是约束——你很难写出奇奇怪怪的内联样式或难以维护的 CSS 类名。配合 TypeScript 的类名提示样式这块也能做到一定程度的“自动检查”。我在实际项目里还配了一套设计 token颜色、间距、字号都从配置文件里取团队新人写页面时基本不用猜设计稿数值。**tRPC 是这套体系里最“灵魂”的一层。**它把后端的函数调用直接暴露给前端前端调用一个异步方法就像调用一个本地函数一样入参、出参全部自动推断。以前写 REST API 时要手动维护 OpenAPI 规范、生成类型定义、处理各种序列化问题在 tRPC 里这些全部消失。Prisma 是数据层的最后一块拼图。它用 schema 文件定义数据模型然后自动生成 TypeScript 类型数据库表结构一旦修改生成的 client 类型同步更新。这样数据库层面的变化能一路传导到最前端的组件里。1.3 与传统前后端分离方案的对比很多人会问我现在的项目是 React 前端 Spring Boot/Node 后端 手写接口文档为什么非要折腾这套我拿一个典型的“用户信息修改”功能来对比。传统方案下这个功能涉及的文件和环节大概有前端表单组件、前端请求封装、后端路由、后端控制器、后端服务层、后端数据模型、接口文档、类型定义手工拷贝。一次改动要同步修改八处漏一处就是线上事故。在t3code里同样一个功能涉及的是前端表单组件、tRPC 路由里的一个 mutation 方法、Prisma 模型。前端调用updateProfile.mutateAsync(...)时传入字段、返回结构都已经被编译器盯死。更关键的是少掉的不仅是文件数量而是一整类“人肉同步错误”。我把两种方式的差异整理成了一张表对比维度传统前后端分离t3codeT3体系接口契约人工维护文档/OpenAPI由代码类型自动生成类型同步手工拷贝、易失效编译期自动推导联调成本依赖 Postman/Swagger 反复比对几乎为零类型即契约改动响应链路后端→文档→前端→联调改后端前端马上报错提醒新人上手成本需要理解两套技术栈语义一套 TypeScript 走到底当然纯 tRPC 方案也有不适合的场景比如要实现完全开放的第三方公开 API或者需要严格的接口版本管理那些场景下 REST/GraphQL 仍然有不可替代的位置。T3 的定位很明确面向“内部业务系统、全栈应用、快速迭代产品”在这个区域内它的效率优势非常突出。2. 环境安装与项目初始化从零拉起一个完整的T3工程2.1 创建项目create-t3-app 的交互选项逐项拆解T3 官方提供了一个脚手架命令create-t3-app我建议所有人都从它开始不要手动拼装。手动搭会遇到一个很尴尬的问题Next.js、tRPC、Prisma 三者之间的初始化顺序和版本兼容性在社区版本迭代频繁的时期极易出现依赖冲突脚手架把这些坑替你处理好了。执行命令很简单npm create t3-applatest my-t3code接下来 CLI 会问你一串交互问题我把我实际选择的配置列出来并解释每一项背后的考虑。项目名称和目录直接按规范来npm 包名不支持大写所以项目名里尽量用短横线分隔。TypeScript or JavaScript这个不用纠结选 TypeScript。T3 的整套设计都建立在类型系统之上选 JavaScript 等于把核心武器扔了。Next.js 的 App Router 还是 Pages Router我选的是 App Router。App Router 是 Next.js 当前主推的目录结构支持 Server Components、流式渲染、更细粒度的缓存控制。虽然 Pages Router 更成熟、相关教程更多但新项目没有历史包袱没必要在旧体系里起步。Tailwind CSS选上。它的 JIT 编译模式让开发体验很好配合 Prettier 插件自动排序类名样式代码非常整齐。tRPC选上。没有它这套方案就不成立了。它会在项目里生成一个完整的 API 层骨架包括 Router 定义、Context 创建、React Query 集成。Prisma选上。T3 官方推荐用 Prisma 作为 ORM因为它的 schema 声明方式跟 TypeScript 的类型哲学天然契合。如果你有别的数据库层偏好可以不走 Prisma但我之后讲的数据链路会围绕它展开。Next Auth这个看情况。如果你的项目需要邮件密码、OAuthGitHub、Google 之类登录建议选上如果是一个纯内部工具不需要复杂鉴权体系可以先跳过。t3code里我选上了 NextAuth因为后续要接入团队账号体系。ESLint / Prettier必须选上。这俩不是可选项是工程质量的底线。T3 脚手架生成的 ESLint 配置里带了不少 Next.js 和 TypeScript 的推荐规则能提前拦截很多低级错误。选完这些之后CLI 会帮你装依赖并生成基础文件。这一步如果网络状况不好可能会卡在某些依赖包上常见的处理方式是切到镜像源或者删掉node_modules和 lock 文件重新安装。我用的是 npm 自带的缓存第一次跑完整构建大概花了三分钟属于正常水平。2.2 初始化后的目录结构每一层放什么脚手架完成后你会看到这样一个核心目录结构my-t3code/ ├── prisma/ │ └── schema.prisma ├── src/ │ ├── app/ │ │ ├── api/ │ │ │ └── trpc/ │ │ │ └── [trpc]/ │ │ ├── layout.tsx │ │ └── page.tsx │ ├── server/ │ │ ├── api/ │ │ │ ├── routers/ │ │ │ └── trpc.ts │ │ └── auth.ts │ ├── trpc/ │ │ ├── server.ts │ │ └── react.tsx │ └── env.js ├── next.config.js ├── tailwind.config.ts └── tsconfig.json很多第一次接触 T3 的人会被这一堆目录吓到觉得文件特别多。实际上每个文件职责非常清楚src/app是页面层Next.js App Router 的页面组件都在这里src/server/api/routers是服务端的 tRPC 路由定义相当于传统项目里的 Controller Servicesrc/server/api/trpc.ts是 tRPC 的初始化文件负责创建 caller、中间件、上下文src/trpc/server.ts是服务端调用 tRPC 的统一入口供 Server Component 和 Server Action 使用src/trpc/react.tsx是前端 React 侧的 Provider 封装把 tRPC client 和 React Query 绑在一起prisma/schema.prisma是数据库模型定义文件。这个结构的核心原则是**“一切围绕数据流分层”**页面不直接操作数据库页面通过 tRPC 调用服务端函数服务端函数通过 Prisma 访问数据库。每层之间的边界非常清晰debug 的时候能快速定位问题。我还额外加了几个目录src/server/services放业务逻辑比如计算用户积分、处理订单状态机src/types放跨层共享的纯类型定义src/config放业务配置项。这么做是因为如果业务逻辑都堆在 router 里router 文件会迅速膨胀到几千行维护性很差。经验之谈tRPC 的 router 应该保持薄业务逻辑下沉到 service。2.3 环境变量与环境校验T3 的一个隐藏优点T3 脚手架会生成一个env.js配合zod做环境变量的运行时校验。这是 T3 体系里很不起眼但极其有价值的设计。传统 Node 项目里环境变量用错比如把DATABASE_URL写成了DATA_BASE_URL通常要到运行时连数据库才报错甚至有的错误会在生产环境静默发生。T3 的做法是在服务启动前用 zod 定义的 schema 校验所有环境变量缺失或格式不对会直接抛出带有清晰消息的错误。import { z } from zod; export const env createEnv({ server: { DATABASE_URL: z.string().url(), NEXTAUTH_SECRET: z.string().min(32), }, client: { NEXT_PUBLIC_APP_NAME: z.string().optional(), }, runtimeEnv: { DATABASE_URL: process.env.DATABASE_URL, NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET, NEXT_PUBLIC_APP_NAME: process.env.NEXT_PUBLIC_APP_NAME, }, });对于NEXTAUTH_SECRETzod 的.min(32)不是拍脑袋定的NextAuth 官方要求 secret 至少 32 个字符否则会有安全隐患。这种“把校验规则写进环境变量声明”的思路比单纯依赖.env.example文件要可靠得多——至少错误发生在构建期而不是线上。3. 核心链路实操从数据库模型到页面渲染的完整管道这一节是全文的核心。我会用一个真实的业务场景——“团队项目任务管理”的某个功能片段来串起整条链路从 Prisma 模型开始到 tRPC 路由再到 React 组件消费完整展示这套类型安全管道怎么运转。3.1 数据模型层用 Prisma Schema 定下“数据宪法”我先在prisma/schema.prisma里定义两张表一张是用户扩展信息表一张是任务表。之所以不直接用 NextAuth 默认的 User 模型是因为业务字段比如昵称、部门不该污染认证模型通过1:1关联扩展更干净。model UserProfile { id String id default(cuid()) userId String unique displayName String department String? createdAt DateTime default(now()) updatedAt DateTime updatedAt } model Task { id String id default(cuid()) title String description String? status TaskStatus default(TODO) assigneeId String? dueDate DateTime? createdAt DateTime default(now()) updatedAt DateTime updatedAt assignee UserProfile? relation(fields: [assigneeId], references: [id]) } enum TaskStatus { TODO IN_PROGRESS DONE }定义好模型后执行迁移命令把 schema 同步到数据库npx prisma migrate dev --name init_task_table这条命令做三件事生成迁移 SQL 文件、执行迁移、重新生成 Prisma Client。重点来了prisma generate会在node_modules/.prisma/client下生成完整的 TypeScript 类型之后你写任何查询代码时IDE 都能提示出所有表字段并且返回结果类型完全受控。我踩过的坑有次我改了 schema 里的字段名但忘了执行迁移结果前端页面还在用旧字段类型检查没报错因为 Prisma Client 还是旧的运行时却拿到了undefined。后来我养成了一个习惯改 schema 之后立刻跑npx prisma migrate dev或者至少在编辑器里用npx prisma generate刷新类型。这个“类型未刷新”的问题在团队协作时特别容易发生建议把prisma generate加到项目的postinstall脚本里。3.2 服务端路由层定义 tRPC Procedure 作为业务入口基础数据结构定了接下来写 tRPC 路由。t3code里的 tRPC 路由分两层一个根路由appRouter下面挂各种子路由如taskRouter、userRouter。子路由里再定义query查询和mutation变更。先看src/server/api/routers/task.tsimport { z } from zod; import { createTRPCRouter, protectedProcedure } from ~/server/api/trpc; const createTaskSchema z.object({ title: z.string().min(1, 任务标题不能为空).max(100), description: z.string().max(2000).optional(), assigneeId: z.string().cuid().optional(), dueDate: z.date().optional(), }); export const taskRouter createTRPCRouter({ list: protectedProcedure .query(async ({ ctx }) { return ctx.db.task.findMany({ orderBy: { createdAt: desc }, include: { assignee: true }, }); }), create: protectedProcedure .input(createTaskSchema) .mutation(async ({ ctx, input }) { return ctx.db.task.create({ data: input, }); }), });这里有几个设计细节值得单独说明。第一protectedProcedure和publicProcedure的区别。protectedProcedure会先执行会话校验未登录用户的请求直接拒绝不会进入业务函数体。这是 T3 官方推荐的做法涉及用户数据和写操作的路由一律用保护流程只有公开信息比如公告页才用公开流程。**第二输入校验直接用 zod schema不需要单独的校验层。**zod 的min(1)、max(100)这些约束会在运行时生效同时它的类型可以反推出input的类型。这样“校验逻辑”和“类型定义”合二为一世界上不会存在“代码里的校验规则”和“文档里的校验规则”不一致的情况。**第三prisma 的类型可以帮助你“写对”查询。**比如include: { assignee: true }这一句如果你写错了关联名编译器立刻报错。数据库层面的外键关系被完整地投影到了 TypeScript 类型里。我额外提一下list接口的返回结构。因为包含了assignee关联返回数组的每一项都是Task { assignee: UserProfile | null }这个类型。前端拿到这个类型后渲染task.assignee.displayName时不会出现“作家本人都不确定这个字段存在”的尴尬。3.3 前端消费层在 React 组件里“直接调用”后端函数现在来到最让人兴奋的一层。前端页面组件通过src/trpc/react.tsx提供的api对象直接调用服务端 procedure。use client; import { api } from ~/trpc/react; export function TaskList() { const { data: tasks, isLoading, error } api.task.list.useQuery(); if (isLoading) return div classNamep-4 text-gray-500加载中.../div; if (error) return div classNamep-4 text-red-500加载失败{error.message}/div; return ( ul classNamedivide-y divide-gray-200 {tasks?.map((task) ( li key{task.id} classNamepy-3 flex items-center justify-between div p classNamefont-medium{task.title}/p p classNametext-sm text-gray-500 负责人{task.assignee?.displayName ?? 未分配} /p /div span classNametext-xs text-gray-400{task.status}/span /li ))} /ul ); }这个组件的写法看起来跟用 React Query 请求 REST 接口一模一样但背后完全不同。api.task.list.useQuery()的入参类型和出参类型全部由 tRPC Router 自动推断。后端如果把list的返回结构改了比如去掉assignee关联前端这里的task.assignee?.displayName会在编译期直接报错。这意味着什么意味着“联调”这个环节基本上被消灭了。前端不需要问后端“这个接口返回什么字段”因为编辑器已经把答案告诉他了后端也不需要问前端“你传的字段名是什么”因为前端调用时传的参数已经被强类型约束。t3code里我还有一个更复杂的例子创建任务的表单组件。这里把 zod schema 直接复用到前端做校验一套规则两端使用连校验措辞都保持一致use client; import { useForm } from react-hook-form; import { zodResolver } from hookform/resolvers/zod; import { createTaskSchema } from ~/shared/schemas/task; import { api } from ~/trpc/react; export function CreateTaskForm() { const utils api.useUtils(); const createTask api.task.create.useMutation({ onSuccess: async () { await utils.task.list.invalidate(); }, }); const { register, handleSubmit, formState: { errors } } useForm({ resolver: zodResolver(createTaskSchema), }); return ( form onSubmit{handleSubmit((data) { createTask.mutate({ ...data, dueDate: data.dueDate ? new Date(data.dueDate) : undefined, }); })} classNamespace-y-4 input {...register(title)} placeholder任务标题 className... / {errors.title p classNametext-red-500{errors.title.message}/p} input {...register(assigneeId)} placeholder负责人ID className... / button typesubmit disabled{createTask.isPending} className... {createTask.isPending ? 提交中... : 创建任务} /button /form ); }useMutation里的onSuccess调用utils.task.list.invalidate()作用是让 React Query 重新拉取任务列表。这就是 T3 体系里“数据变更后刷新页面”的标准动作不需要手动管理缓存失效一个 invalidate 调用解决。这里的~/shared/schemas/task是我在项目里专门抽出来的一个模块。既然 zod schema 能同时服务前后端就没必要在 server 和 client 各写一份。把它放在一个共享目录里天然规避“两套校验规则漂移”的问题。这是t3code里我做的一个关键架构决策强烈建议大家抄作业。3.4 全链路数据流演示创建任务到页面刷新把上面的代码串起来t3code里“创建一个任务”的完整流程是用户在前端表单填写标题、选择负责人React Hook Form 通过zodResolver校验输入不合法直接在表单下方显示错误合法数据作为input传给api.task.create.useMutation().mutate()tRPC client 把入参序列化后发送到 Next.js API 路由/api/trpc/*服务端先执行protectedProcedure的会话校验通过后zod 在 server 端再次校验入参双端校验防止绕过前端直接请求校验通过后调用ctx.db.task.create({ data: input })写入数据库返回创建后的完整任务对象给前端onSuccess回调触发invalidate()任务列表自动刷新。整个过程我从“用户点击提交”到“列表出现新任务”肉眼感知不到任何中间环节因为它本来就是一次完整的函数调用。而这种“直觉上的简单”恰恰是背后每一层都做了正确约束的结果。4. 常见问题与排查技巧实录4.1 Prisma 类型不同步改了 schema 但前端没反应这是 T3 项目里出现频率最高的问题。场景一般是你改了schema.prisma的字段保存后去写代码发现 IDE 还是提示旧字段或者运行时报“Column not found”。原因大概率不是代码错了而是 Prisma Client 没有重新生成。Prisma 的特点是你的代码引用的类型来自自动生成的 Client而不是 schema 文件本身。生成动作需要手动执行npx prisma generate如果改了表结构还要先迁移npx prisma migrate dev --name update_task_assignee排查建议确认node_modules/.prisma/client的生成时间是否晚于 schema 修改时间确认你用的是prisma/client而不是prisma后者是 CLI 工具包不包含运行时 client在 CI/CD 流程里构建前一定要执行prisma generate我甚至建议在package.json的postinstall里加一句省得每个人本地都忘。4.2 tRPC 类型推导“卡住”过程型数据拿不到类型新手很容易在inferRouterOutputs或者跨路由引用类型时遇到 TS 报错很多的情况。比如你想在前端取task.list的返回类型import type { RouterOutputs } from ~/trpc/react; type Task RouterOutputs[task][list][number];这个写法理论上没问题但如果你在src/trpc/react.tsx里没有正确导出RouterOutputs就会报“类型空间不存在该属性”。T3 脚手架默认生成的src/trpc/react.tsx里有一行export type RouterOutputs ReturnTypetypeof appRouter.createCaller;如果你手动改过文件的目录结构或删除了某些导出这个类型链就会断掉。排查时先看appRouter的导出路径是否正确再看createTRPCContext的返回类型。4.3 Next.js 部署时常见的“普适性迷思”Client/Server 边界App Router 模式下最容易踩的坑是你随手在组件里 import 了一个函数结果这个函数依赖 Node.js 环境比如prisma组件又被标记成了use client构建直接失败。报错信息通常会提示 “PrismaClient is not configured to run in the browser” 之类。出现这种问题明确一个原则所有涉及数据库、涉及服务端上下文的代码绝对不能出现在客户端组件里。解决方式如果这个组件只是为了展示数据改成 Server Component去掉use client在服务端调用 tRPC caller如果组件必须交互有useState、事件处理把数据获取逻辑留给父级 Server Component通过 props 传入如果你需要在客户端调用 tRPC用src/trpc/react里的 hooks而不是直接 import server 代码。t3code里我遇到过一次很隐蔽的问题一个“用户详情弹窗”组件在弹窗打开时才请求数据我把它写成了客户端组件又在里面直接用了prisma查询结果构建成功但浏览器里疯狂报错。后来改成让弹窗组件只接收userId数据请求通过 tRPC hook 完成问题才根治。4.4 冷门但很实用的几个经验这里分享几个我在t3code里亲测有用的细节属于看书看不来的那类。第一tRPC 的错误信息要做二次封装。默认的 TRPCError 会把新增字段、校验信息都抛出来生产环境直接暴露内部表名字段并不合适。我在trpc.ts里加了一层错误映射中间件把ZodError、PrismaClientKnownRequestError统一转成对外安全的错误消息同时记录一份完整的服务端日志。上线之后排查错误效率高很多。第二用useUtils().myRouter.invalidate()做局部缓存刷新。很多初学者喜欢刷新整个页面来同步数据在 T3 里没必要。React Query 的缓存是键值库invalidate可以精准到某个 procedure。这个习惯养成后页面切换的感知速度会明显提升。第三把 zod schema 的“正则校验”用在业务敏感字段上。比如手机号、工号我都在 schema 里定义好合法格式前后端共用。这样不仅减少重复代码还能保证数据在入库存根之前就符合业务规则。配合 TypeScript 的 literal 类型还能把枚举状态如TaskStatus在前后端一起约束住。第四本地开发时给 tRPC 开启日志。tRPC 提供了loggerLink我在 server 端的 tRPC 初始化时默认开启 dev 日志能看到每一次 procedure 调用的耗时、入参大小、错误堆栈。这个小改动对定位性能问题帮助极大比事后查监控舒服得多。5. 工具链选型与团队协作中的几个补充心得5.1 状态管理为什么t3code里没有 Redux 和 Zustand刚上手 T3 的人经常会问状态管理用什么Redux 还是 Zustand我的回答是本地 UI 状态用 React 自带的 hooks 就够了服务端状态交给 React Query全局共享状态基本用不上第三方库。在 T3 架构里服务端状态用户信息、任务列表、设置项全部由 React Query 缓存管理你不需要把它再复制一份进 Redux store。Redux 擅长的是“复杂的前端状态流转”但大部分业务页面的状态需求其实是“从服务器拿数据、展示、提交变更”这正好是 React Query tRPC 的主场。t3code里只有一处用了 Zustand一个记录“当前侧边栏是否折叠”的 UI 状态。这种跟服务端无关、跟路由无关的轻量状态用一个小 store 就够了。这算是我的选型原则先问这个状态从哪来再决定它放哪。5.2 数据库策略SQLite 起步还是直接上 PostgreSQLT3 脚手架默认支持 SQLite这对本地开发极其友好零配置、跑起来就能用。但生产环境如果业务会增长我建议直接用 PostgreSQL。t3code的演进路径是从 SQLite 起步做原型验证切到 PostgreSQL 时只改了一行DATABASE_URL因为 Prisma 屏蔽了大部分数据库方言差异。当然要小心索引、全文检索这类 SQLite 和 PostgreSQL 差异较大的功能在前期设计时就要有意识避开。5.3 代码组织上的“团队默契”T3 给了你很好的骨架但真正的工程化还得靠约定。我在团队里推行了三条简单规则所有 zod schema 统一放在src/shared/schemas禁止散落在组件文件里所有业务逻辑写在src/server/servicesrouter 里只做参数校验和调用转发所有跨组件复用的类型在src/types里显式声明不要靠编辑器自动推断链去读。这些规则跟框架无关但配合 T3 的类型体系能让整个项目保持“改了 A 就会立刻提示你改 B”的连锁反应。新人在这种环境里写代码犯错的成本被压到很低因为类型系统和大目录约束已经把最容易出错的路径堵死了。最后再说说我自己这段时间的真实感受。从传统接口联调切到 tRPC Prisma 这套全栈类型安全方案后我最大的变化是以前最害怕的“改接口”现在反而是最省心的事。因为改一个返回字段时编译器会告诉我所有受影响的地方而不是等测试同学来报告。这也是我把这个项目命名为t3code的原因——用 T3 的方式写代码本质上是用类型系统把一部分测试工作前移让开发者在“写代码”而不是“猜代码”。如果你也在维护一个快速迭代、内部业务为主的全栈项目我建议你拿一个小模块先试点感受一下“类型即契约”的开发节奏。等你在终端里看到那串红色波浪线替自己挡住了线上 bug你就明白这套体系为什么值得投入了。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询