Build fully typed APIs with createTRPCRouter, publicProcedure, useQuery, useMutation, and TypeScript inference without code generation
0 / 5 completed
1 / 5
How does createTRPCRouter establish type safety in a tRPC application?
createTRPCRouter: You define procedures with input schemas (typically Zod) and resolver functions. The inferred return types of resolvers and input schemas form a RouterOutputs/RouterInputs type. The client imports only this type — not the server code — so TypeScript can check API calls at compile time with zero runtime overhead.
2 / 5
What does publicProcedure represent in tRPC and how is it extended?
publicProcedure: is typically created via t.procedure. Extend it: const authedProcedure = publicProcedure.use(({ ctx, next }) => { if (!ctx.user) throw new TRPCError({ code: 'UNAUTHORIZED' }); return next({ ctx: { ...ctx, user: ctx.user } }); }). Each extension narrows the context type, so TypeScript guarantees ctx.user is non-null inside authedProcedure resolvers.
3 / 5
How does tRPC's useQuery hook on the client maintain type safety?
tRPC useQuery: Example: const { data } = trpc.user.getById.useQuery({ id: 1 }) — data is typed as the resolver's return type with no manual annotation. If you pass a wrong input type (e.g. { id: 'abc' } when number is expected), TypeScript flags it at compile time. No generated files, no GraphQL schema, no OpenAPI spec.
4 / 5
What is the purpose of useMutation in tRPC?
tRPC useMutation:const mutation = trpc.user.create.useMutation({ onSuccess: () => utils.user.list.invalidate() }). Call mutation.mutate({ name: 'Alice' }) — input is typed. mutation.data, mutation.error, and mutation.isPending are all available with correct types. The onSuccess pattern integrates naturally with React Query's cache invalidation.
5 / 5
How does tRPC achieve type inference without code generation?
Zero codegen: In the client config, you pass type AppRouter = typeof appRouter as a generic parameter. tRPC's client types use TypeScript's mapped and conditional types to derive each procedure's input/output. Because it's pure TypeScript inference, IDE autocomplete and type errors work instantly — no build step, no generated .ts files to maintain.