You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

运行时如何区分tRPC的DecoratedMutation与DecoratedQuery?

运行时如何区分tRPC的DecoratedMutation与DecoratedQuery?

我之前也踩过这个坑!tRPC React客户端返回的DecoratedQuery和DecoratedMutation都是用Proxy包装的,所以直接检查useQuery或useMutation属性是否存在根本没用——Proxy会拦截所有属性访问,不管实际有没有都会返回一个占位函数,导致你看到的结果全是true。

下面给你两个靠谱的解决方案,按推荐程度排序:


方案一:给服务端Procedure添加Meta元数据(最可控、最兼容)

这是我最推荐的方法,完全不受tRPC版本或Proxy实现的影响,自己能完全掌控判断逻辑。

  1. 修改服务端的router定义,给每个Procedure加上meta字段标记类型:
// app/trpc.ts
import { initTRPC } from '@trpc/server';
import { createTRPCReact } from '@trpc/react-query';
import { z } from 'zod';

const t = initTRPC.create();

export const appRouter = t.router({
  hello: t.procedure
    .meta({ procedureType: 'query' }) // 标记为查询类型
    .query(() => 'world'),
  add: t.procedure
    .input(z.object({ x: z.number(), y: z.number() }))
    .meta({ procedureType: 'mutation' }) // 标记为突变类型
    .mutation(({ input }) => input.x + input.y),
});

// 其余代码保持不变
export type AppRouter = typeof appRouter;
export const trpc = createTRPCReact<AppRouter>();
  1. 在客户端写两个运行时判断函数:
// 可以放在app/trpc.ts或者单独的工具文件里
function isDecoratedQuery(procedure: unknown): boolean {
  return (procedure as any)?._def?.meta?.procedureType === 'query';
}

function isDecoratedMutation(procedure: unknown): boolean {
  return (procedure as any)?._def?.meta?.procedureType === 'mutation';
}
  1. 然后在组件里测试:
// app/page.tsx
'use client';
import React from 'react';
import { trpc } from './trpc';

export default function Page() {
  const helloProcedure = trpc.hello;
  const addProcedure = trpc.add;

  console.log('helloProcedure 是查询吗?', isDecoratedQuery(helloProcedure)); // true
  console.log('addProcedure 是突变吗?', isDecoratedMutation(addProcedure)); // true

  return (
    <div>
      <h1>Minimal Reproducible Example Application</h1>
      <p>Open console to see the correct checks.</p>
    </div>
  );
}

方案二:直接检查客户端Procedure的_def内部字段(依赖tRPC实现,更简洁)

如果你的tRPC 11.x版本允许客户端访问_def字段,可以直接通过检查_def里是否存在query或mutation函数来判断,不需要修改服务端代码:

// 运行时判断函数
function isDecoratedQuery(procedure: unknown): boolean {
  return typeof (procedure as any)?._def?.query === 'function';
}

function isDecoratedMutation(procedure: unknown): boolean {
  return typeof (procedure as any)?._def?.mutation === 'function';
}

直接在组件里用这两个函数就行,测试结果会和预期一致。不过要注意:这个方法依赖tRPC客户端的内部实现,如果未来tRPC调整了_def的结构,可能会失效,所以追求长期稳定性的话,还是方案一更稳妥。


为什么你原来的方法没用?

再补一句踩坑的原因:tRPC客户端为了实现类型安全的自动提示,用Proxy包装了所有Procedure。当你访问任何属性(比如useMutation)时,Proxy的get陷阱会自动返回一个占位函数,所以不管是Query还是Mutation,useQuery/useMutation都会存在——但你真的调用这些函数时,Query类型的Procedure调用useMutation会报错,反之亦然。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 09:10:28