Inferring Types
It is often useful to wrap functionality of your @trpc/client
or @trpc/react-query
api within other functions. For this purpose, it's necessary to be able to infer input types and output types generated by your @trpc/server
router.
Inference Helpers
@trpc/server
exports the following helper types to assist with inferring these types from the AppRouter
exported by your @trpc/server
router:
inferRouterInputs<TRouter>
inferRouterOutputs<TRouter>
Let's assume we have this example router:
server.tsts
// @filename: server.tsimport {initTRPC } from '@trpc/server';import {z } from "zod";constt =initTRPC .create ();constappRouter =t .router ({post :t .router ({list :t .procedure .query (() => {// imaginary db callreturn [{id : 1,title : 'tRPC is the best!' }];}),byId :t .procedure .input (z .string ()).query (({input }) => {// imaginary db callreturn {id : 1,title : 'tRPC is the best!' };}),create :t .procedure .input (z .object ({title :z .string (),text :z .string (), })).mutation (({input }) => {// imaginary db callreturn {id : 1, ...input };}),}),});export typeAppRouter = typeofappRouter ;
server.tsts
// @filename: server.tsimport {initTRPC } from '@trpc/server';import {z } from "zod";constt =initTRPC .create ();constappRouter =t .router ({post :t .router ({list :t .procedure .query (() => {// imaginary db callreturn [{id : 1,title : 'tRPC is the best!' }];}),byId :t .procedure .input (z .string ()).query (({input }) => {// imaginary db callreturn {id : 1,title : 'tRPC is the best!' };}),create :t .procedure .input (z .object ({title :z .string (),text :z .string (), })).mutation (({input }) => {// imaginary db callreturn {id : 1, ...input };}),}),});export typeAppRouter = typeofappRouter ;
By traversing the router object, you can infer the types of the procedures. The following example shows how to infer the types of the procedures using the example appRouter
:
client.tsts
// @filename: client.tsimport type {inferRouterInputs ,inferRouterOutputs } from '@trpc/server';import type {AppRouter } from './server';typeRouterInput =inferRouterInputs <AppRouter >;typeRouterOutput =inferRouterOutputs <AppRouter >;typePostCreateInput =RouterInput ['post']['create'];typePostCreateOutput =RouterOutput ['post']['create'];
client.tsts
// @filename: client.tsimport type {inferRouterInputs ,inferRouterOutputs } from '@trpc/server';import type {AppRouter } from './server';typeRouterInput =inferRouterInputs <AppRouter >;typeRouterOutput =inferRouterOutputs <AppRouter >;typePostCreateInput =RouterInput ['post']['create'];typePostCreateOutput =RouterOutput ['post']['create'];
Infer TRPClientError
s based on your router
client.tsts
// @filename: client.tsimport {TRPCClientError } from '@trpc/client';import type {AppRouter } from './server';import {trpc } from './trpc';export functionisTRPCClientError (cause : unknown,):cause isTRPCClientError <AppRouter > {returncause instanceofTRPCClientError ;}async functionmain () {try {awaittrpc .post .byId .query ('1');} catch (cause ) {if (isTRPCClientError (cause )) {// `cause` is now typed as your router's `TRPCClientError`console .log ('data',cause .data );} else {// [...]}}}main ();
client.tsts
// @filename: client.tsimport {TRPCClientError } from '@trpc/client';import type {AppRouter } from './server';import {trpc } from './trpc';export functionisTRPCClientError (cause : unknown,):cause isTRPCClientError <AppRouter > {returncause instanceofTRPCClientError ;}async functionmain () {try {awaittrpc .post .byId .query ('1');} catch (cause ) {if (isTRPCClientError (cause )) {// `cause` is now typed as your router's `TRPCClientError`console .log ('data',cause .data );} else {// [...]}}}main ();
Infer React Query options based on your router
When creating custom hooks around tRPC procedures, it's sometimes necesary to have the types of the options inferred from the router. You can do so via the inferReactQueryProcedureOptions
helper exported from @trpc/react-query
.
ts
// @filename: trpc.tsimport {typeinferReactQueryProcedureOptions ,createTRPCReact } from '@trpc/react-query';import type {inferRouterInputs } from '@trpc/server';import type {AppRouter } from './server';export typeReactQueryOptions =inferReactQueryProcedureOptions <AppRouter >;export typeRouterInputs =inferRouterInputs <AppRouter >;export consttrpc =createTRPCReact <AppRouter >();// @filename: usePostCreate.tsimport { typeReactQueryOptions ,trpc } from './trpc';typePostCreateOptions =ReactQueryOptions ['post']['create'];functionusePostCreate (options ?:PostCreateOptions ) {constutils =trpc .useContext ();returntrpc .post .create .useMutation ({...options ,onSuccess (post ) {// invalidate all queries on the post router// when a new post is createdutils .post .invalidate ();options ?.onSuccess ?.(post );},});}// @filename: usePostById.tsimport {ReactQueryOptions ,RouterInputs ,trpc } from './trpc';typePostByIdOptions =ReactQueryOptions ['post']['byId'];typePostByIdInput =RouterInputs ['post']['byId'];functionusePostById (input :PostByIdInput ,options ?:PostByIdOptions ) {returntrpc .post .byId .useQuery (input ,options );}
ts
// @filename: trpc.tsimport {typeinferReactQueryProcedureOptions ,createTRPCReact } from '@trpc/react-query';import type {inferRouterInputs } from '@trpc/server';import type {AppRouter } from './server';export typeReactQueryOptions =inferReactQueryProcedureOptions <AppRouter >;export typeRouterInputs =inferRouterInputs <AppRouter >;export consttrpc =createTRPCReact <AppRouter >();// @filename: usePostCreate.tsimport { typeReactQueryOptions ,trpc } from './trpc';typePostCreateOptions =ReactQueryOptions ['post']['create'];functionusePostCreate (options ?:PostCreateOptions ) {constutils =trpc .useContext ();returntrpc .post .create .useMutation ({...options ,onSuccess (post ) {// invalidate all queries on the post router// when a new post is createdutils .post .invalidate ();options ?.onSuccess ?.(post );},});}// @filename: usePostById.tsimport {ReactQueryOptions ,RouterInputs ,trpc } from './trpc';typePostByIdOptions =ReactQueryOptions ['post']['byId'];typePostByIdInput =RouterInputs ['post']['byId'];functionusePostById (input :PostByIdInput ,options ?:PostByIdOptions ) {returntrpc .post .byId .useQuery (input ,options );}