Inferring Types
In addition to the type inference made available by @trpc/server (see here) this integration also provides some inference helpers for usage purely in React.
Infer React Query options based on your router
When creating custom hooks around tRPC procedures, it's sometimes necessary to have the types of the options inferred from the router. You can do so via the inferReactQueryProcedureOptions helper exported from @trpc/react-query.
trpc.tstsimport {createTRPCReact ,typeinferReactQueryProcedureOptions ,} from '@trpc/react-query';import type {inferRouterInputs ,inferRouterOutputs } from '@trpc/server';import type {AppRouter } from './server';// infer the types for your routerexport typeReactQueryOptions =inferReactQueryProcedureOptions <AppRouter >;export typeRouterInputs =inferRouterInputs <AppRouter >;export typeRouterOutputs =inferRouterOutputs <AppRouter >;export consttrpc =createTRPCReact <AppRouter >();
trpc.tstsimport {createTRPCReact ,typeinferReactQueryProcedureOptions ,} from '@trpc/react-query';import type {inferRouterInputs ,inferRouterOutputs } from '@trpc/server';import type {AppRouter } from './server';// infer the types for your routerexport typeReactQueryOptions =inferReactQueryProcedureOptions <AppRouter >;export typeRouterInputs =inferRouterInputs <AppRouter >;export typeRouterOutputs =inferRouterOutputs <AppRouter >;export consttrpc =createTRPCReact <AppRouter >();
usePostCreate.tstsimport {trpc ,typeReactQueryOptions ,typeRouterInputs ,typeRouterOutputs ,} from './trpc';typePostCreateOptions =ReactQueryOptions ['post']['create'];functionusePostCreate (options ?:PostCreateOptions ) {constutils =trpc .useUtils ();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 );},});}
usePostCreate.tstsimport {trpc ,typeReactQueryOptions ,typeRouterInputs ,typeRouterOutputs ,} from './trpc';typePostCreateOptions =ReactQueryOptions ['post']['create'];functionusePostCreate (options ?:PostCreateOptions ) {constutils =trpc .useUtils ();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 );},});}
usePostById.tstsimport {ReactQueryOptions ,RouterInputs ,trpc } from './trpc';typePostByIdOptions =ReactQueryOptions ['post']['byId'];typePostByIdInput =RouterInputs ['post']['byId'];functionusePostById (input :PostByIdInput ,options ?:PostByIdOptions ) {returntrpc .post .byId .useQuery (input ,options );}
usePostById.tstsimport {ReactQueryOptions ,RouterInputs ,trpc } from './trpc';typePostByIdOptions =ReactQueryOptions ['post']['byId'];typePostByIdInput =RouterInputs ['post']['byId'];functionusePostById (input :PostByIdInput ,options ?:PostByIdOptions ) {returntrpc .post .byId .useQuery (input ,options );}
Infer abstract types from a "Router Factory"
If you write a factory which creates a similar router interface several times in your application, you may wish to share client code between usages of the factory. @trpc/react-query/shared exports several types which can be used to generate abstract types for a router factory, and build common React components which are passed the router as a prop.
api/factory.tstsximport {t ,publicProcedure } from './trpc';// @trpc/react-query/shared exports several **Like types which can be used to generate abstract typesimport {RouterLike ,UtilsLike } from '@trpc/react-query/shared';// Factory function written by you, however you need,// so long as you can infer the resulting type of t.router() laterexport functioncreateMyRouter () {returnt .router ({createThing :publicProcedure .input (ThingRequest ).output (Thing ).mutation (/* do work */),listThings :publicProcedure .input (ThingQuery ).output (ThingArray ).query (/* do work */),})}// Infer the type of your router, and then generate the abstract types for use in the clienttypeMyRouterType =ReturnType <typeofcreateMyRouter >exportMyRouterLike =RouterLike <MyRouterType >exportMyRouterUtilsLike =UtilsLike <MyRouterType >
api/factory.tstsximport {t ,publicProcedure } from './trpc';// @trpc/react-query/shared exports several **Like types which can be used to generate abstract typesimport {RouterLike ,UtilsLike } from '@trpc/react-query/shared';// Factory function written by you, however you need,// so long as you can infer the resulting type of t.router() laterexport functioncreateMyRouter () {returnt .router ({createThing :publicProcedure .input (ThingRequest ).output (Thing ).mutation (/* do work */),listThings :publicProcedure .input (ThingQuery ).output (ThingArray ).query (/* do work */),})}// Infer the type of your router, and then generate the abstract types for use in the clienttypeMyRouterType =ReturnType <typeofcreateMyRouter >exportMyRouterLike =RouterLike <MyRouterType >exportMyRouterUtilsLike =UtilsLike <MyRouterType >
api/server.tstsxexport typeAppRouter = typeofappRouter ;// Export your MyRouter types to the clientexport type {MyRouterLike ,MyRouterUtilsLike } from './factory';
api/server.tstsxexport typeAppRouter = typeofappRouter ;// Export your MyRouter types to the clientexport type {MyRouterLike ,MyRouterUtilsLike } from './factory';
frontend/usePostCreate.tstsximport type {MyRouterLike ,MyRouterUtilsLike ,trpc ,useUtils } from './trpc';typeMyGenericComponentProps = {route :MyRouterLike ;utils :MyRouterUtilsLike ;};functionMyGenericComponent (props :MyGenericComponentProps ) {const {route } =props ;constthing =route .listThings .useQuery ({filter : 'qwerty',});constmutation =route .doThing .useMutation ({onSuccess () {props .utils .listThings .invalidate ();},});functionhandleClick () {mutation .mutate ({name : 'Thing 1',});}return; /* ui */}functionMyPageComponent () {constutils =useUtils ();return (<MyGenericComponent route ={trpc . deep .route .things }utils ={utils . deep .route .things }/>);}functionMyOtherPageComponent () {constutils =useUtils ();return (<MyGenericComponent route ={trpc . different .things }utils ={utils . different .things }/>);}
frontend/usePostCreate.tstsximport type {MyRouterLike ,MyRouterUtilsLike ,trpc ,useUtils } from './trpc';typeMyGenericComponentProps = {route :MyRouterLike ;utils :MyRouterUtilsLike ;};functionMyGenericComponent (props :MyGenericComponentProps ) {const {route } =props ;constthing =route .listThings .useQuery ({filter : 'qwerty',});constmutation =route .doThing .useMutation ({onSuccess () {props .utils .listThings .invalidate ();},});functionhandleClick () {mutation .mutate ({name : 'Thing 1',});}return; /* ui */}functionMyPageComponent () {constutils =useUtils ();return (<MyGenericComponent route ={trpc . deep .route .things }utils ={utils . deep .route .things }/>);}functionMyOtherPageComponent () {constutils =useUtils ();return (<MyGenericComponent route ={trpc . different .things }utils ={utils . different .things }/>);}
A more complete working example can be found here