如何在TRPC中自定义JSON序列化?解决BigInt校验失败问题
在TRPC中自定义JSON序列化处理BigInt问题
你之前全局修改BigInt.prototype.toJSON的方式会导致所有BigInt被转成字符串,TRPC传输后Zod校验时因为期望BigInt类型而失败。正确的做法是在TRPC层面自定义序列化逻辑,而非全局污染原型链,下面是两种可行方案:
方案一:使用superjson(推荐)
superjson是TRPC官方推荐的序列化工具,原生支持BigInt、Date等类型的双向转换,无需手动处理递归:
- 安装依赖
npm install superjson
- 配置TRPC服务端
在创建TRPC router时指定transformer为superjson:
import { initTRPC } from '@trpc/server'; import superjson from 'superjson'; const t = initTRPC.create({ transformer: superjson, }); export const router = t.router; export const publicProcedure = t.procedure;
- 配置TRPC客户端
在客户端初始化时同步使用superjson:
import { createTRPCReact } from '@trpc/react-query'; import type { AppRouter } from '../server'; import superjson from 'superjson'; export const trpc = createTRPCReact<AppRouter>(); // 初始化client的示例(React项目) export function useTRPC() { return trpc.useClient({ url: '/api/trpc', transformer: superjson, }); }
- Zod校验适配
直接使用z.bigint()定义校验规则即可,superjson会自动把传输过程中的字符串转回BigInt:
import { z } from 'zod'; const getByIdProcedure = publicProcedure .input(z.object({ userId: z.bigint(), })) .query(({ input }) => { // input.userId 是BigInt类型,可直接使用 return { userId: input.userId }; });
方案二:手动实现自定义序列化器
如果不想引入额外依赖,可以手动编写TRPC的transformer函数,通过标记法处理BigInt:
import { initTRPC } from '@trpc/server'; const t = initTRPC.create({ transformer: { // 序列化:把BigInt转成带标记的对象 serialize: (data) => { const replacer = (_key: string, value: unknown) => { if (typeof value === 'bigint') { return { __type: 'bigint', value: value.toString() }; } return value; }; return JSON.stringify(data, replacer); }, // 反序列化:把带标记的对象转回BigInt deserialize: (data) => { const reviver = (_key: string, value: unknown) => { if ( typeof value === 'object' && value !== null && '__type' in value && (value as any).__type === 'bigint' && 'value' in value ) { return BigInt((value as any).value); } return value; }; return JSON.parse(data, reviver); }, }, });
这种方式需要自己处理数据的递归遍历,适合对依赖体积有严格要求的场景。
内容的提问来源于stack exchange,提问作者Luis Angel Perez
相关产品推荐
相关产品推荐

