快速入门
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
安装
tRPC 被拆分为多个独立包,您只需按需安装所需组件。请确保在代码库的适当位置安装目标包。为简化快速入门指南,我们将仅使用原生客户端。若需框架集成指南,请查阅 React 集成方案 和 Next.js 集成方案。
- tRPC 要求 TypeScript >=5.7.2
- 强烈建议在
tsconfig.json中设置"strict": true,官方不支持非严格模式
首先安装 @trpc/server 和 @trpc/client 这两个核心依赖包:
- npm
- yarn
- pnpm
- bun
- deno
npm install @trpc/server @trpc/client
yarn add @trpc/server @trpc/client
pnpm add @trpc/server @trpc/client
bun add @trpc/server @trpc/client
deno add npm:@trpc/server npm:@trpc/client
若使用 AI 编程助手,请安装 tRPC 技能以优化代码生成:
bashnpx @tanstack/intent@latest install
bashnpx @tanstack/intent@latest install
创建首个 tRPC API
接下来我们将逐步构建类型安全的 tRPC API。初始API包含三个端点,其 TypeScript 类型定义如下:
tstype User = { id: string; name: string; };userList: () => User[];userById: (id: string) => User;userCreate: (data: { name: string }) => User;
tstype User = { id: string; name: string; };userList: () => User[];userById: (id: string) => User;userCreate: (data: { name: string }) => User;
以下是我们将构建的文件结构。建议将 tRPC 初始化、路由定义和服务器配置分离到独立文件,避免循环依赖:
.├── server/│ ├── trpc.ts # tRPC instantiation & setup│ ├── appRouter.ts # Your API logic and type export│ └── index.ts # HTTP server└── client/└── index.ts # tRPC client
.├── server/│ ├── trpc.ts # tRPC instantiation & setup│ ├── appRouter.ts # Your API logic and type export│ └── index.ts # HTTP server└── client/└── index.ts # tRPC client
1. 创建路由实例
首先初始化 tRPC 后端。最佳实践是在独立文件中完成此操作,并导出可复用的辅助函数而非整个 tRPC 对象。
server/trpc.tstsimport {initTRPC } from '@trpc/server';/*** Initialization of tRPC backend* Should be done only once per backend!*/constt =initTRPC .create ();/*** Export reusable router and procedure helpers* that can be used throughout the router*/export constrouter =t .router ;export constpublicProcedure =t .procedure ;
server/trpc.tstsimport {initTRPC } from '@trpc/server';/*** Initialization of tRPC backend* Should be done only once per backend!*/constt =initTRPC .create ();/*** Export reusable router and procedure helpers* that can be used throughout the router*/export constrouter =t .router ;export constpublicProcedure =t .procedure ;
接下来初始化主路由实例(通常命名为 appRouter),后续将向其添加过程。最后需导出路由类型,供客户端后续使用。
server/appRouter.tstsimport {router } from './trpc';export constappRouter =router ({// ...});export typeAppRouter = typeofappRouter ;
server/appRouter.tstsimport {router } from './trpc';export constappRouter =router ({// ...});export typeAppRouter = typeofappRouter ;
2. 添加查询过程
使用 publicProcedure.query() 方法向路由添加查询过程。
以下代码创建名为 userList 的查询过程,用于返回用户列表:
server/appRouter.tstsimport {publicProcedure ,router } from './trpc';export constappRouter =router ({userList :publicProcedure .query (async () => {constusers :User [] = [{id : '1',name : 'Katt' }];returnusers ;}),});export typeAppRouter = typeofappRouter ;
server/appRouter.tstsimport {publicProcedure ,router } from './trpc';export constappRouter =router ({userList :publicProcedure .query (async () => {constusers :User [] = [{id : '1',name : 'Katt' }];returnusers ;}),});export typeAppRouter = typeofappRouter ;
3. 使用输入解析器验证参数
要实现 userById 过程,需要接收客户端输入。tRPC 允许您定义输入解析器来验证和解析输入。您可以使用自定义解析器或第三方验证库,例如 zod、yup 或 superstruct。
在 publicProcedure.input() 中定义输入解析器,解析结果可通过解析器函数访问:
- Vanilla
- Zod
- Yup
- Valibot
The input parser should be a function that validates and casts the input of this procedure. It should return a strongly typed value when the input is valid or throw an error if the input is invalid.
Throughout the remainder of this documentation, we will use zod as our validation library.
server/appRouter.tstsimport {publicProcedure ,router } from './trpc';export constappRouter =router ({// ...userById :publicProcedure // The input is unknown at this time. A client could have sent// us anything so we won't assume a certain data type..input ((val : unknown) => {// If the value is of type string, return it.// It will now be inferred as a string.if (typeofval === 'string') returnval ;// Uh oh, looks like that input wasn't a string.// We will throw an error instead of running the procedure.throw newError (`Invalid input: ${typeofval }`);}).query (async (opts ) => {const {input } =opts ;constuser :User = {id :input ,name : 'Katt' };returnuser ;}),});export typeAppRouter = typeofappRouter ;
server/appRouter.tstsimport {publicProcedure ,router } from './trpc';export constappRouter =router ({// ...userById :publicProcedure // The input is unknown at this time. A client could have sent// us anything so we won't assume a certain data type..input ((val : unknown) => {// If the value is of type string, return it.// It will now be inferred as a string.if (typeofval === 'string') returnval ;// Uh oh, looks like that input wasn't a string.// We will throw an error instead of running the procedure.throw newError (`Invalid input: ${typeofval }`);}).query (async (opts ) => {const {input } =opts ;constuser :User = {id :input ,name : 'Katt' };returnuser ;}),});export typeAppRouter = typeofappRouter ;
The input parser can be any ZodType, e.g. z.string() or z.object().
server/appRouter.tstsimport {publicProcedure ,router } from './trpc';import {z } from 'zod';export constappRouter =router ({// ...userById :publicProcedure .input (z .string ()).query (async (opts ) => {const {input } =opts ;constuser :User = {id :input ,name : 'Katt' };returnuser ;}),});export typeAppRouter = typeofappRouter ;
server/appRouter.tstsimport {publicProcedure ,router } from './trpc';import {z } from 'zod';export constappRouter =router ({// ...userById :publicProcedure .input (z .string ()).query (async (opts ) => {const {input } =opts ;constuser :User = {id :input ,name : 'Katt' };returnuser ;}),});export typeAppRouter = typeofappRouter ;
The input parser can be any YupSchema, e.g. yup.string() or yup.object().
Throughout the remainder of this documentation, we will use zod as our validation library.
server/appRouter.tstsimport {publicProcedure ,router } from './trpc';import * asyup from 'yup';export constappRouter =router ({// ...userById :publicProcedure .input (yup .string ().required ()).query (async (opts ) => {const {input } =opts ;constuser :User = {id :input ,name : 'Katt' };returnuser ;}),});export typeAppRouter = typeofappRouter ;
server/appRouter.tstsimport {publicProcedure ,router } from './trpc';import * asyup from 'yup';export constappRouter =router ({// ...userById :publicProcedure .input (yup .string ().required ()).query (async (opts ) => {const {input } =opts ;constuser :User = {id :input ,name : 'Katt' };returnuser ;}),});export typeAppRouter = typeofappRouter ;
The input parser can be any Valibot schema, e.g. v.string() or v.object().
Throughout the remainder of this documentation, we will use zod as our validation library.
server/appRouter.tstsimport {publicProcedure ,router } from './trpc';import * asv from 'valibot';export constappRouter =router ({// ...userById :publicProcedure .input (v .string ()).query (async (opts ) => {const {input } =opts ;constuser :User = {id :input ,name : 'Katt' };returnuser ;}),});export typeAppRouter = typeofappRouter ;
server/appRouter.tstsimport {publicProcedure ,router } from './trpc';import * asv from 'valibot';export constappRouter =router ({// ...userById :publicProcedure .input (v .string ()).query (async (opts ) => {const {input } =opts ;constuser :User = {id :input ,name : 'Katt' };returnuser ;}),});export typeAppRouter = typeofappRouter ;
4. 添加变更过程
与 GraphQL 类似,tRPC 明确区分查询(Query)和变更(Mutation)过程。
查询与变更的核心区别在于语义:查询使用 HTTP GET 方法执行读取操作,变更使用 HTTP POST 方法执行会产生副作用的操作。
通过向路由对象添加新属性来创建 userCreate 变更过程:
server/appRouter.tstsimport {publicProcedure ,router } from './trpc';export constappRouter =router ({// ...userCreate :publicProcedure .input (z .object ({name :z .string () })).mutation (async (opts ) => {const {input } =opts ;// Create the user in your DBconstuser :User = {id : '1', ...input };returnuser ;}),});export typeAppRouter = typeofappRouter ;
server/appRouter.tstsimport {publicProcedure ,router } from './trpc';export constappRouter =router ({// ...userCreate :publicProcedure .input (z .object ({name :z .string () })).mutation (async (opts ) => {const {input } =opts ;// Create the user in your DBconstuser :User = {id : '1', ...input };returnuser ;}),});export typeAppRouter = typeofappRouter ;
部署 API
路由定义完成后即可部署服务。tRPC 提供一流的适配器支持主流 Web 服务器。为简化操作,此处使用 standalone Node.js 适配器。
server/index.tstsimport {createHTTPServer } from '@trpc/server/adapters/standalone';import {appRouter } from './appRouter';constserver =createHTTPServer ({router :appRouter ,});server .listen (3000);
server/index.tstsimport {createHTTPServer } from '@trpc/server/adapters/standalone';import {appRouter } from './appRouter';constserver =createHTTPServer ({router :appRouter ,});server .listen (3000);
See the full backend code
server/trpc.tstsimport {initTRPC } from '@trpc/server';constt =initTRPC .create ();export constrouter =t .router ;export constpublicProcedure =t .procedure ;
server/trpc.tstsimport {initTRPC } from '@trpc/server';constt =initTRPC .create ();export constrouter =t .router ;export constpublicProcedure =t .procedure ;
server/appRouter.tstsimport {z } from "zod";import {publicProcedure ,router } from "./trpc";typeUser = {id : string;name : string };export constappRouter =router ({userList :publicProcedure .query (async () => {constusers :User [] = [{id : '1',name : 'Katt' }];returnusers ;}),userById :publicProcedure .input (z .string ()).query (async (opts ) => {const {input } =opts ;constuser :User = {id :input ,name : 'Katt' };returnuser ;}),userCreate :publicProcedure .input (z .object ({name :z .string () })).mutation (async (opts ) => {const {input } =opts ;constuser :User = {id : '1', ...input };returnuser ;}),});export typeAppRouter = typeofappRouter ;
server/appRouter.tstsimport {z } from "zod";import {publicProcedure ,router } from "./trpc";typeUser = {id : string;name : string };export constappRouter =router ({userList :publicProcedure .query (async () => {constusers :User [] = [{id : '1',name : 'Katt' }];returnusers ;}),userById :publicProcedure .input (z .string ()).query (async (opts ) => {const {input } =opts ;constuser :User = {id :input ,name : 'Katt' };returnuser ;}),userCreate :publicProcedure .input (z .object ({name :z .string () })).mutation (async (opts ) => {const {input } =opts ;constuser :User = {id : '1', ...input };returnuser ;}),});export typeAppRouter = typeofappRouter ;
server/index.tstsimport {createHTTPServer } from "@trpc/server/adapters/standalone";import {appRouter } from "./appRouter";constserver =createHTTPServer ({router :appRouter ,});server .listen (3000);
server/index.tstsimport {createHTTPServer } from "@trpc/server/adapters/standalone";import {appRouter } from "./appRouter";constserver =createHTTPServer ({router :appRouter ,});server .listen (3000);
在客户端使用后端服务
现在让我们转到客户端代码,体验端到端类型安全的强大功能。当我们将 AppRouter 类型导入客户端使用时,整个系统就实现了完整的类型安全,同时不会向客户端泄露任何实现细节。
1. 设置 tRPC 客户端
client/index.tstsimport {createTRPCClient ,httpBatchLink } from '@trpc/client';import type {AppRouter } from './appRouter';// 👆 **type-only** imports are stripped at build time// Pass AppRouter as a type parameter. 👇 This lets `trpc` know// what procedures are available on the server and their input/output types.consttrpc =createTRPCClient <AppRouter >({links : [httpBatchLink ({url : 'http://localhost:3000',}),],});
client/index.tstsimport {createTRPCClient ,httpBatchLink } from '@trpc/client';import type {AppRouter } from './appRouter';// 👆 **type-only** imports are stripped at build time// Pass AppRouter as a type parameter. 👇 This lets `trpc` know// what procedures are available on the server and their input/output types.consttrpc =createTRPCClient <AppRouter >({links : [httpBatchLink ({url : 'http://localhost:3000',}),],});
tRPC 的链接(Links)机制类似 GraphQL,用于控制数据流向服务器。上例使用的 httpBatchLink 可自动将多个请求合并为单个 HTTP 调用。深入使用请参阅链接文档。
2. 类型推断与自动补全
现在您可以通过 trpc 对象访问您的 API 过程。立即尝试吧!
client/index.tsts// Inferred typesconstuser = awaittrpc .userById .query ('1');constcreatedUser = awaittrpc .userCreate .mutate ({name : 'Katt' });
client/index.tsts// Inferred typesconstuser = awaittrpc .userById .query ('1');constcreatedUser = awaittrpc .userCreate .mutate ({name : 'Katt' });
您还可通过自动补全功能在客户端探索 API
client/index.tststrpc .u ;
client/index.tststrpc .u ;
后续步骤
| What's next? | Description |
|---|---|
| Example Apps | Explore tRPC in your chosen framework |
| TanStack React Query | Recommended React integration via @trpc/tanstack-react-query |
| Next.js | Usage with Next.js |
| Server Adapters | Express, Fastify, and more |
| Transformers | Use superjson to retain complex types like Date |