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

TRPC v10如何实现含短横线的路由路径?

TRPC v10 中短横线分隔路由的简洁实现方式

v9 与 v10 的路由定义差异

在 TRPC v9 中,路由采用链式调用定义:

const appRouter = trpc.router()
  .query('greeting', {
    input: z.string(),
    resolve({ input }) {
      return `hello ${input}!`;
    },
  });

到了 TRPC v10,路由改为对象字面量形式:

const appRouter = router({
  greeting: publicProcedure
    .input(z.string())
    .query(({ input }) => `hello ${input}!`),
});

问题:短横线分隔路由的调用繁琐

如果要实现 register-user 这类短横线分隔的路由,常规写法在前后端都不够简洁:

服务端代码

// server-side
const userRouter = router({
  ["register-user"]: procedure
    .input(registerUserInputSchema)
    .mutation(async ({ ctx, input }) => {
      // 业务逻辑实现
    }),
});

前端调用代码

// fe-side
function RegisterPage() {
  const { handleSubmit, register } = useForm();
  // 因路由合并带有 users 前缀(详见附录)
  const {} = trpc["users"]["register-user"].useMutation();

  return (
    <>
      <form action=""></form>
      <Link href="/login">Login</Link>
    </>
  );
}

这种写法必须用方括号访问属性,不够直观,下面提供两种更简洁的实现思路:

解决方案1:用 alias 指定路径别名

TRPC v10 支持通过 alias 方法为路由设置自定义路径,服务端用驼峰式命名保持代码整洁,同时对外暴露短横线分隔的路径:

// server-side
const userRouter = router({
  registerUser: procedure
    .input(registerUserInputSchema)
    .mutation(async ({ ctx, input }) => {
      // 业务逻辑实现
    })
    .alias("register-user"), // 对外暴露短横线分隔的路径
});

前端调用时直接用驼峰式点语法即可:

// fe-side
function RegisterPage() {
  const { handleSubmit, register } = useForm();
  const {} = trpc.users.registerUser.useMutation();

  return (
    <>
      <form action=""></form>
      <Link href="/login">Login</Link>
    </>
  );
}

解决方案2:中间件自动转换路径格式

如果不想逐个设置别名,可以编写中间件,自动将驼峰式路由名转为短横线分隔的路径:

// 自定义路径转换中间件
const kebabCaseMiddleware = t.middleware(async ({ ctx, next, path }) => {
  // 驼峰转短横线格式
  const kebabPath = path.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase();
  return next({
    ctx,
    path: kebabPath,
  });
});

// 将中间件应用到全局 procedure
const publicProcedure = t.procedure.use(kebabCaseMiddleware);

// 服务端用驼峰式定义路由
const userRouter = router({
  registerUser: publicProcedure
    .input(registerUserInputSchema)
    .mutation(async ({ ctx, input }) => {
      // 业务逻辑实现
    }),
});

这种方式下,前端依然用简洁的点语法调用,外部访问的路径会自动转为 register-user 格式。

附录:users. 前缀的由来

调用路由时的 users. 前缀,是因为根路由中合并了用户子路由:

import { router } from "../trpc";
import { userRouter } from "./user.router";

export const appRouter = router({
  users: userRouter, // 合并用户路由,因此前端调用需加 users 前缀
});

export type AppRouter = typeof appRouter;

内容的提问来源于stack exchange,提问作者netlemon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 22:10:10