mh
mh3mo ago

Types issues upgrading to v11, `never` when using t.router

Hi, we have a mono repo project that we are trying to upgrade from v10.45.2 to v11(next). However, we are running into a weird types issue. This codebase was/is working completely fine with v10.45.2 but upgrading package versions seems to be causing types issues. Maybe we have missed something. We have a base trpc defined in a shared package trpc-shared.
import { initTRPC } from "@trpc/server";
import { setupHttpLogging } from "../http/log.js";
import type { Context } from "./context.js";

const t = initTRPC.context<Context>().create();

const { router, middleware, mergeRouters } = t;
const procedure = t.procedure.use(async (opts) => {
const { ctx, next } = opts;
const { request, response } = ctx;
setupHttpLogging(request, response);
// some additional setup...
const result = await next(...);

return result;
});

export { router, middleware, mergeRouters, procedure };
import { initTRPC } from "@trpc/server";
import { setupHttpLogging } from "../http/log.js";
import type { Context } from "./context.js";

const t = initTRPC.context<Context>().create();

const { router, middleware, mergeRouters } = t;
const procedure = t.procedure.use(async (opts) => {
const { ctx, next } = opts;
const { request, response } = ctx;
setupHttpLogging(request, response);
// some additional setup...
const result = await next(...);

return result;
});

export { router, middleware, mergeRouters, procedure };
Now, over in our api project, we consume the router to create some endpoints.
import { Context, procedure, router } from "trpc-server-shared"; // our shared project
import { type inferRouterInputs } from "@trpc/server";

export const appRouter = router({
health: router({ check: procedure.query(() => ({ healthy: "ok" })) })
});

type AppRouter = typeof appRouter;
type AppRouterInputs = inferRouterInputs<AppRouter>;
import { Context, procedure, router } from "trpc-server-shared"; // our shared project
import { type inferRouterInputs } from "@trpc/server";

export const appRouter = router({
health: router({ check: procedure.query(() => ({ healthy: "ok" })) })
});

type AppRouter = typeof appRouter;
type AppRouterInputs = inferRouterInputs<AppRouter>;
However, the type of AppRouterInputs is
type AppRouterInputs = {
health: never;
}
type AppRouterInputs = {
health: never;
}
The types were working fine with v10.45.2 and the only change is the package updates, no other code changes (and based on the migration guide and our current existing code base, no breaking changes were affecting our codebase). Clearing node_modules and reinstalling/rebuilding does not help.
"@trpc/client": "next",
"@trpc/server": "next",
"@trpc/client": "next",
"@trpc/server": "next",
3 Replies
mh
mhOP3mo ago
Weird thing is, if I use initTrpc directly in the api project in the exact same way as in the shared project, the types start working.
import { Context, procedure } from "trpc-server-shared";
import { initTRPC, type inferRouterInputs } from "@trpc/server";

const t = initTRPC.context<Context>().create();
// don't use router from shared package, note t.router. procedure can still be from shared package
export const appRouter = t.router({
health: t.router({ check: procedure.query(() => ({ healthy: "ok" })) })
});

type AppRouter = typeof appRouter;
type AppRouterInputs = inferRouterInputs<AppRouter>;
import { Context, procedure } from "trpc-server-shared";
import { initTRPC, type inferRouterInputs } from "@trpc/server";

const t = initTRPC.context<Context>().create();
// don't use router from shared package, note t.router. procedure can still be from shared package
export const appRouter = t.router({
health: t.router({ check: procedure.query(() => ({ healthy: "ok" })) })
});

type AppRouter = typeof appRouter;
type AppRouterInputs = inferRouterInputs<AppRouter>;
Now AppRouterInputs has correct typing instead of never We are using typescript 5.6.2, node v22.9.0, pnpm v9.12.0 and have sctrict: true, also have
"declaration": true,
"declarationMap": true,
"declaration": true,
"declarationMap": true,
Lounès
Lounès5w ago
Seems related to https://discord.com/channels/867764511159091230/1091331399551828078/1091331399551828078. I'm facing the same issue, only for nested routers. If I merge two routers instead of nesting them, typings work as expected. okay, if i use router({}) only for the top-level router, and just a plain object for the nested ones, everything seems good
Lounès
Lounès5w ago
https://trpc.io/docs/server/merging-routers#inline-sub-router as per the doc, both should work but only using the plain object doesn't infer the router to never
Merging Routers | tRPC
Writing all API-code in your code in the same file is not a great idea. It's easy to merge routers with other routers.

Did you find this page helpful?