rembrembdocs

It is often useful to access the types of your API within your clients. For this purpose, you are able to infer the types contained in your AppRouter.

@trpc/server exports the following helper types to assist with inferring these types from the AppRouter exported by your @trpc/server router:

Inferring Input & Output Types

Let's assume we have this example router:

server.ts

ts

import { initTRPC } from '@trpc/server';

import { z } from "zod";

const t = initTRPC.create();

const appRouter = t.router({

post: t.router({

`list: t.procedure`

  `.query(() => {`

    `// imaginary db call`

    `return [{ id: 1, title: 'tRPC is the best!' }];`

`}),`

`byId: t.procedure`

  `.input(z.string())`

  `.query((opts) => {`

    `// imaginary db call`

    `return { id: 1, title: 'tRPC is the best!' };`

`}),`

`create: t.procedure`

  `.input(z.object({ title: z.string(), text: z.string(), }))`

  `.mutation((opts) => {`

    `// imaginary db call`

    `return { id: 1, ...opts.input };`

`}),`

`onPostAdd: t.procedure`

  `.input(z.object({ authorId: z.string() }))`

  `.subscription(async function* ({ input }) {`

    `// imaginary event source`

    `yield {`

      `id: 1,`

      `title: 'tRPC is the best!',`

      `authorId: input.authorId,`

    `};`

`}),`

}),

});

export type AppRouter = typeof appRouter;

Using the helpers, we can infer the types of our router. The following example shows how to infer the types of the post.create procedure:

client.ts

ts

import type { inferRouterInputs, inferRouterOutputs } from '@trpc/server';

import type { AppRouter } from './server';

type RouterInput = inferRouterInputs<AppRouter>;

type RouterOutput = inferRouterOutputs<AppRouter>;

type PostCreateInput = RouterInput['post']['create'];

type PostCreateOutput = RouterOutput['post']['create'];

Inferring Individual Procedure Types

If you already have access to a specific procedure on your router, you can infer its input or output directly:

client.ts

ts

import type {

inferProcedureInput,

inferProcedureOutput,

} from '@trpc/server';

import type { AppRouter } from './server';

type PostByIdInput = inferProcedureInput<AppRouter['post']['byId']>;

type PostByIdOutput = inferProcedureOutput<AppRouter['post']['byId']>;

For subscriptions, you can infer the subscription input and the emitted data type:

client.ts

ts

import type {

inferSubscriptionInput,

inferSubscriptionOutput,

} from '@trpc/server';

import type { AppRouter } from './server';

type OnPostAddInput = inferSubscriptionInput<AppRouter['post']['onPostAdd']>;

type OnPostAddOutput = inferSubscriptionOutput<AppRouter['post']['onPostAdd']>;

Infer TRPCClientError types

It's also useful to infer the error type for your AppRouter

client.ts

ts

import { TRPCClientError } from '@trpc/client';

import type { AppRouter } from './server';

import { trpc } from './trpc';

export function isTRPCClientError(

cause: unknown,

): cause is TRPCClientError<AppRouter> {

return cause instanceof TRPCClientError;

}

async function main() {

try {

`await trpc.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();