Skip to content
tRPC

Inferring Types

On this page

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:

  • inferRouterInputs<TRouter>
  • inferRouterOutputs<TRouter>
  • inferProcedureInput<TProcedure>
  • inferProcedureOutput<TProcedure>
  • inferSubscriptionInput<TProcedure>
  • inferSubscriptionOutput<TProcedure>

Inferring Input & Output Types

Let's assume we have this example router:

server.ts

import { const initTRPC: TRPCBuilder<object, object>initTRPC } from '@trpc/server';
import { import zz } from "zod";

const 
const t: TRPCRootObject<object, object, RuntimeConfigOptions<object, object>, {
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}>
t
= const initTRPC: TRPCBuilder<object, object>initTRPC.
TRPCBuilder<object, object>.create<RuntimeConfigOptions<object, object>>(opts?: RuntimeConfigOptions<object, object> | undefined): TRPCRootObject<object, object, RuntimeConfigOptions<object, object>, {
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}>
create
();
const
const appRouter: BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: number;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        byId: QueryProcedure<{
            input: string;
            output: {
                id: number;
                title: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        create: MutationProcedure<{
            input: {
                title: string;
                text: string;
            };
            output: {
                ...;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        onPostAdd: SubscriptionProcedure<...>;
    }>>;
}>>
appRouter
=
const t: TRPCRootObject<object, object, RuntimeConfigOptions<object, object>, {
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}>
t
.
TRPCRootObject<object, object, RuntimeConfigOptions<object, object>, { ctx: object; meta: object; errorShape: DefaultErrorShape; transformer: false; }>.router: RouterBuilder
<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: number;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        byId: QueryProcedure<{
            input: string;
            output: {
                id: number;
                title: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        create: MutationProcedure<{
            input: {
                title: string;
                text: string;
            };
            output: {
                title: string;
                text: string;
                id: number;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        onPostAdd: SubscriptionProcedure<...>;
    }>>;
}>(_: {
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: number;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        byId: QueryProcedure<{
            input: string;
            output: {
                id: number;
                title: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        create: MutationProcedure<{
            input: {
                title: string;
                text: string;
            };
            output: {
                title: string;
                text: string;
                id: number;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        onPostAdd: SubscriptionProcedure<...>;
    }>>;
}) => BuiltRouter<...>
router
({
post: BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    list: QueryProcedure<{
        input: void;
        output: {
            id: number;
            title: string;
        }[];
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    byId: QueryProcedure<{
        input: string;
        output: {
            id: number;
            title: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    create: MutationProcedure<{
        input: {
            title: string;
            text: string;
        };
        output: {
            ...;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    onPostAdd: SubscriptionProcedure<...>;
}>>
post
:
const t: TRPCRootObject<object, object, RuntimeConfigOptions<object, object>, {
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}>
t
.
TRPCRootObject<object, object, RuntimeConfigOptions<object, object>, { ctx: object; meta: object; errorShape: DefaultErrorShape; transformer: false; }>.router: RouterBuilder
<{
    list: QueryProcedure<{
        input: void;
        output: {
            id: number;
            title: string;
        }[];
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    byId: QueryProcedure<{
        input: string;
        output: {
            id: number;
            title: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    create: MutationProcedure<{
        input: {
            title: string;
            text: string;
        };
        output: {
            title: string;
            text: string;
            id: number;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    onPostAdd: SubscriptionProcedure<{
        input: {
            authorId: string;
        };
        output: AsyncIterable<{
            id: number;
            title: string;
            authorId: string;
        }, void, any>;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}>(_: {
    list: QueryProcedure<{
        input: void;
        output: {
            id: number;
            title: string;
        }[];
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    byId: QueryProcedure<{
        input: string;
        output: {
            id: number;
            title: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    create: MutationProcedure<{
        input: {
            title: string;
            text: string;
        };
        output: {
            title: string;
            text: string;
            id: number;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    onPostAdd: SubscriptionProcedure<{
        input: {
            authorId: string;
        };
        output: AsyncIterable<{
            id: number;
            title: string;
            authorId: string;
        }, void, any>;
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
}) => BuiltRouter<...>
router
({
list: QueryProcedure<{
    input: void;
    output: {
        id: number;
        title: string;
    }[];
    meta: object;
    errorShape: DefaultErrorShape;
}>
list
:
const t: TRPCRootObject<object, object, RuntimeConfigOptions<object, object>, {
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}>
t
.TRPCRootObject<object, object, RuntimeConfigOptions<object, object>, { ctx: object; meta: object; errorShape: DefaultErrorShape; transformer: false; }>.procedure: ProcedureBuilder<object, object, object, UnsetMarker, UnsetMarker, UnsetMarker, UnsetMarker, false, DefaultErrorShape>procedure
.
ProcedureBuilder<object, object, object, UnsetMarker, UnsetMarker, UnsetMarker, UnsetMarker, false, DefaultErrorShape>.query<{
    id: number;
    title: string;
}[]>(resolver: ProcedureResolver<object, object, object, UnsetMarker, UnsetMarker, {
    id: number;
    title: string;
}[]>): QueryProcedure<{
    input: void;
    output: {
        id: number;
        title: string;
    }[];
    meta: object;
    errorShape: DefaultErrorShape;
}>
query
(() => {
// imaginary db call return [{ id: numberid: 1, title: stringtitle: 'tRPC is the best!' }]; }),
byId: QueryProcedure<{
    input: string;
    output: {
        id: number;
        title: string;
    };
    meta: object;
    errorShape: DefaultErrorShape;
}>
byId
:
const t: TRPCRootObject<object, object, RuntimeConfigOptions<object, object>, {
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}>
t
.TRPCRootObject<object, object, RuntimeConfigOptions<object, object>, { ctx: object; meta: object; errorShape: DefaultErrorShape; transformer: false; }>.procedure: ProcedureBuilder<object, object, object, UnsetMarker, UnsetMarker, UnsetMarker, UnsetMarker, false, DefaultErrorShape>procedure
.ProcedureBuilder<object, object, object, UnsetMarker, UnsetMarker, UnsetMarker, UnsetMarker, false, DefaultErrorShape>.input<z.ZodString>(schema: z.ZodString): ProcedureBuilder<object, object, object, string, string, UnsetMarker, UnsetMarker, false, DefaultErrorShape>input(import zz.function string(params?: string | z.core.$ZodStringParams): z.ZodString (+1 overload)string()) .
ProcedureBuilder<object, object, object, string, string, UnsetMarker, UnsetMarker, false, DefaultErrorShape>.query<{
    id: number;
    title: string;
}>(resolver: ProcedureResolver<object, object, object, string, UnsetMarker, {
    id: number;
    title: string;
}>): QueryProcedure<{
    input: string;
    output: {
        id: number;
        title: string;
    };
    meta: object;
    errorShape: DefaultErrorShape;
}>
query
((opts: ProcedureResolverOptions<object, object, object, string>opts) => {
// imaginary db call return { id: numberid: 1, title: stringtitle: 'tRPC is the best!' }; }),
create: MutationProcedure<{
    input: {
        title: string;
        text: string;
    };
    output: {
        ...;
    };
    meta: object;
    errorShape: DefaultErrorShape;
}>
create
:
const t: TRPCRootObject<object, object, RuntimeConfigOptions<object, object>, {
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}>
t
.TRPCRootObject<object, object, RuntimeConfigOptions<object, object>, { ctx: object; meta: object; errorShape: DefaultErrorShape; transformer: false; }>.procedure: ProcedureBuilder<object, object, object, UnsetMarker, UnsetMarker, UnsetMarker, UnsetMarker, false, DefaultErrorShape>procedure
.
ProcedureBuilder<object, object, object, UnsetMarker, UnsetMarker, UnsetMarker, UnsetMarker, false, DefaultErrorShape>.input<z.ZodObject<{
    title: z.ZodString;
    text: z.ZodString;
}, z.core.$strip>>(schema: z.ZodObject<{
    title: z.ZodString;
    text: z.ZodString;
}, z.core.$strip>): ProcedureBuilder<object, object, object, {
    title: string;
    text: string;
}, {
    title: string;
    text: string;
}, UnsetMarker, UnsetMarker, false, DefaultErrorShape>
input
(import zz.
function object<{
    title: z.ZodString;
    text: z.ZodString;
}>(shape?: {
    title: z.ZodString;
    text: z.ZodString;
} | undefined, params?: string | {
    error?: string | z.core.$ZodErrorMap<NonNullable<z.core.$ZodIssueUnrecognizedKeys | z.core.$ZodIssueInvalidType<unknown>>> | undefined;
    message?: string | undefined | undefined;
} | undefined): z.ZodObject<{
    title: z.ZodString;
    text: z.ZodString;
}, z.core.$strip>
object
({ title: z.ZodStringtitle: import zz.function string(params?: string | z.core.$ZodStringParams): z.ZodString (+1 overload)string(), text: z.ZodStringtext: import zz.function string(params?: string | z.core.$ZodStringParams): z.ZodString (+1 overload)string(), }))
.
ProcedureBuilder<object, object, object, { title: string; text: string; }, { title: string; text: string; }, UnsetMarker, UnsetMarker, false, DefaultErrorShape>.mutation<{
    title: string;
    text: string;
    id: number;
}>(resolver: ProcedureResolver<object, object, object, {
    title: string;
    text: string;
}, UnsetMarker, {
    title: string;
    text: string;
    id: number;
}>): MutationProcedure<{
    input: {
        title: string;
        text: string;
    };
    output: {
        title: string;
        text: string;
        id: number;
    };
    meta: object;
    errorShape: DefaultErrorShape;
}>
mutation
((
opts: ProcedureResolverOptions<object, object, object, {
    title: string;
    text: string;
}>
opts
) => {
// imaginary db call return { id: numberid: 1, ...
opts: ProcedureResolverOptions<object, object, object, {
    title: string;
    text: string;
}>
opts
.
ProcedureResolverOptions<object, object, object, { title: string; text: string; }>.input: {
    title: string;
    text: string;
}
input
};
}),
onPostAdd: SubscriptionProcedure<{
    input: {
        authorId: string;
    };
    output: AsyncIterable<{
        id: number;
        title: string;
        authorId: string;
    }, void, any>;
    meta: object;
    errorShape: DefaultErrorShape;
}>
onPostAdd
:
const t: TRPCRootObject<object, object, RuntimeConfigOptions<object, object>, {
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}>
t
.TRPCRootObject<object, object, RuntimeConfigOptions<object, object>, { ctx: object; meta: object; errorShape: DefaultErrorShape; transformer: false; }>.procedure: ProcedureBuilder<object, object, object, UnsetMarker, UnsetMarker, UnsetMarker, UnsetMarker, false, DefaultErrorShape>procedure
.
ProcedureBuilder<object, object, object, UnsetMarker, UnsetMarker, UnsetMarker, UnsetMarker, false, DefaultErrorShape>.input<z.ZodObject<{
    authorId: z.ZodString;
}, z.core.$strip>>(schema: z.ZodObject<{
    authorId: z.ZodString;
}, z.core.$strip>): ProcedureBuilder<object, object, object, {
    authorId: string;
}, {
    authorId: string;
}, UnsetMarker, UnsetMarker, false, DefaultErrorShape>
input
(import zz.
function object<{
    authorId: z.ZodString;
}>(shape?: {
    authorId: z.ZodString;
} | undefined, params?: string | {
    error?: string | z.core.$ZodErrorMap<NonNullable<z.core.$ZodIssueUnrecognizedKeys | z.core.$ZodIssueInvalidType<unknown>>> | undefined;
    message?: string | undefined | undefined;
} | undefined): z.ZodObject<{
    authorId: z.ZodString;
}, z.core.$strip>
object
({ authorId: z.ZodStringauthorId: import zz.function string(params?: string | z.core.$ZodStringParams): z.ZodString (+1 overload)string() }))
.
ProcedureBuilder<object, object, object, { authorId: string; }, { authorId: string; }, UnsetMarker, UnsetMarker, false, DefaultErrorShape>.subscription<AsyncGenerator<{
    id: number;
    title: string;
    authorId: string;
}, void, any>>(resolver: ProcedureResolver<object, object, object, {
    authorId: string;
}, UnsetMarker, AsyncGenerator<{
    id: number;
    title: string;
    authorId: string;
}, void, any>>): SubscriptionProcedure<{
    input: {
        authorId: string;
    };
    output: AsyncIterable<{
        id: number;
        title: string;
        authorId: string;
    }, void, any>;
    meta: object;
    errorShape: DefaultErrorShape;
}> (+1 overload)
subscription
(async function* ({
input: {
    authorId: string;
}
input
}) {
// imaginary event source yield { id: numberid: 1, title: stringtitle: 'tRPC is the best!', authorId: stringauthorId:
input: {
    authorId: string;
}
input
.authorId: stringauthorId,
}; }), }), }); export type
type AppRouter = Router<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: number;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        byId: QueryProcedure<{
            input: string;
            output: {
                id: number;
                title: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        create: MutationProcedure<{
            input: {
                title: string;
                text: string;
            };
            output: {
                ...;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        onPostAdd: SubscriptionProcedure<...>;
    }>>;
}>> & DecorateCreateRouterOptions<...>
AppRouter
= typeof
const appRouter: BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: number;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        byId: QueryProcedure<{
            input: string;
            output: {
                id: number;
                title: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        create: MutationProcedure<{
            input: {
                title: string;
                text: string;
            };
            output: {
                ...;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        onPostAdd: SubscriptionProcedure<...>;
    }>>;
}>>
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
import type { type inferRouterInputs<TRouter extends AnyRouter> = { [TKey in keyof TRouter["_def"]["record"]]: TRouter["_def"]["record"][TKey] extends infer $Value ? $Value extends AnyProcedure ? inferProcedureInput<$Value> : $Value extends RouterRecord ? GetInferenceHelpers<"input", TRouter["_def"]["_config"]["$types"], $Value> : never : never; }inferRouterInputs, type inferRouterOutputs<TRouter extends AnyRouter> = { [TKey in keyof TRouter["_def"]["record"]]: TRouter["_def"]["record"][TKey] extends infer $Value ? $Value extends AnyProcedure ? inferTransformedProcedureOutput<TRouter["_def"]["_config"]["$types"], $Value> : $Value extends RouterRecord ? GetInferenceHelpers<"output", TRouter["_def"]["_config"]["$types"], $Value> : never : never; }inferRouterOutputs } from '@trpc/server';
import type { 
type AppRouter = Router<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: number;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        byId: QueryProcedure<{
            input: string;
            output: {
                id: number;
                title: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        create: MutationProcedure<{
            input: {
                title: string;
                text: string;
            };
            output: {
                ...;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        onPostAdd: SubscriptionProcedure<...>;
    }>>;
}>> & DecorateCreateRouterOptions<...>
AppRouter
} from './server';
type
type RouterInput = {
    post: GetInferenceHelpers<"input", {
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: number;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        byId: QueryProcedure<{
            input: string;
            output: {
                id: number;
                title: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        create: MutationProcedure<{
            input: {
                title: string;
                text: string;
            };
            output: {
                ...;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        onPostAdd: SubscriptionProcedure<...>;
    }>>;
}
RouterInput
= type inferRouterInputs<TRouter extends AnyRouter> = { [TKey in keyof TRouter["_def"]["record"]]: TRouter["_def"]["record"][TKey] extends infer $Value ? $Value extends AnyProcedure ? inferProcedureInput<$Value> : $Value extends RouterRecord ? GetInferenceHelpers<"input", TRouter["_def"]["_config"]["$types"], $Value> : never : never; }inferRouterInputs<
type AppRouter = Router<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: number;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        byId: QueryProcedure<{
            input: string;
            output: {
                id: number;
                title: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        create: MutationProcedure<{
            input: {
                title: string;
                text: string;
            };
            output: {
                ...;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        onPostAdd: SubscriptionProcedure<...>;
    }>>;
}>> & DecorateCreateRouterOptions<...>
AppRouter
>;
type
type RouterOutput = {
    post: GetInferenceHelpers<"output", {
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: number;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        byId: QueryProcedure<{
            input: string;
            output: {
                id: number;
                title: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        create: MutationProcedure<{
            input: {
                title: string;
                text: string;
            };
            output: {
                ...;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        onPostAdd: SubscriptionProcedure<...>;
    }>>;
}
RouterOutput
= type inferRouterOutputs<TRouter extends AnyRouter> = { [TKey in keyof TRouter["_def"]["record"]]: TRouter["_def"]["record"][TKey] extends infer $Value ? $Value extends AnyProcedure ? inferTransformedProcedureOutput<TRouter["_def"]["_config"]["$types"], $Value> : $Value extends RouterRecord ? GetInferenceHelpers<"output", TRouter["_def"]["_config"]["$types"], $Value> : never : never; }inferRouterOutputs<
type AppRouter = Router<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: number;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        byId: QueryProcedure<{
            input: string;
            output: {
                id: number;
                title: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        create: MutationProcedure<{
            input: {
                title: string;
                text: string;
            };
            output: {
                ...;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        onPostAdd: SubscriptionProcedure<...>;
    }>>;
}>> & DecorateCreateRouterOptions<...>
AppRouter
>;
type PostCreateInput =
type RouterInput = {
    post: GetInferenceHelpers<"input", {
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: number;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        byId: QueryProcedure<{
            input: string;
            output: {
                id: number;
                title: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        create: MutationProcedure<{
            input: {
                title: string;
                text: string;
            };
            output: {
                ...;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        onPostAdd: SubscriptionProcedure<...>;
    }>>;
}
RouterInput
['post']['create'];
type PostCreateInput = {
    title: string;
    text: string;
}
type PostCreateOutput =
type RouterOutput = {
    post: GetInferenceHelpers<"output", {
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: number;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        byId: QueryProcedure<{
            input: string;
            output: {
                id: number;
                title: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        create: MutationProcedure<{
            input: {
                title: string;
                text: string;
            };
            output: {
                ...;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        onPostAdd: SubscriptionProcedure<...>;
    }>>;
}
RouterOutput
['post']['create'];
type PostCreateOutput = {
    title: string;
    text: string;
    id: number;
}

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
import type {
  type inferProcedureInput<TProcedure extends AnyProcedure> = undefined extends inferProcedureParams<TProcedure>["$types"]["input"] ? void | inferProcedureParams<TProcedure>["$types"]["input"] : inferProcedureParams<TProcedure>["$types"]["input"]inferProcedureInput,
  type inferProcedureOutput<TProcedure> = inferProcedureParams<TProcedure>["$types"]["output"]inferProcedureOutput,
} from '@trpc/server';
import type { 
type AppRouter = Router<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: number;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        byId: QueryProcedure<{
            input: string;
            output: {
                id: number;
                title: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        create: MutationProcedure<{
            input: {
                title: string;
                text: string;
            };
            output: {
                ...;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        onPostAdd: SubscriptionProcedure<...>;
    }>>;
}>> & DecorateCreateRouterOptions<...>
AppRouter
} from './server';
type PostByIdInput = type inferProcedureInput<TProcedure extends AnyProcedure> = undefined extends inferProcedureParams<TProcedure>["$types"]["input"] ? void | inferProcedureParams<TProcedure>["$types"]["input"] : inferProcedureParams<TProcedure>["$types"]["input"]inferProcedureInput<
type AppRouter = Router<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: number;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        byId: QueryProcedure<{
            input: string;
            output: {
                id: number;
                title: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        create: MutationProcedure<{
            input: {
                title: string;
                text: string;
            };
            output: {
                ...;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        onPostAdd: SubscriptionProcedure<...>;
    }>>;
}>> & DecorateCreateRouterOptions<...>
AppRouter
['post']['byId']>;
type PostByIdInput = string
type PostByIdOutput = type inferProcedureOutput<TProcedure> = inferProcedureParams<TProcedure>["$types"]["output"]inferProcedureOutput<
type AppRouter = Router<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: number;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        byId: QueryProcedure<{
            input: string;
            output: {
                id: number;
                title: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        create: MutationProcedure<{
            input: {
                title: string;
                text: string;
            };
            output: {
                ...;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        onPostAdd: SubscriptionProcedure<...>;
    }>>;
}>> & DecorateCreateRouterOptions<...>
AppRouter
['post']['byId']>;
type PostByIdOutput = {
    id: number;
    title: string;
}

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

client.ts
import type {
  type inferSubscriptionInput<TProcedure extends AnySubscriptionProcedure> = undefined extends inferProcedureParams<TProcedure>["$types"]["input"] ? void | inferProcedureParams<TProcedure>["$types"]["input"] : inferProcedureParams<TProcedure>["$types"]["input"]inferSubscriptionInput,
  type inferSubscriptionOutput<TProcedure extends AnySubscriptionProcedure> = TProcedure extends LegacyObservableSubscriptionProcedure<any> ? inferProcedureOutput<TProcedure> : inferAsyncIterableYield<inferProcedureOutput<TProcedure>>inferSubscriptionOutput,
} from '@trpc/server';
import type { 
type AppRouter = Router<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: number;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        byId: QueryProcedure<{
            input: string;
            output: {
                id: number;
                title: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        create: MutationProcedure<{
            input: {
                title: string;
                text: string;
            };
            output: {
                ...;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        onPostAdd: SubscriptionProcedure<...>;
    }>>;
}>> & DecorateCreateRouterOptions<...>
AppRouter
} from './server';
type OnPostAddInput = type inferSubscriptionInput<TProcedure extends AnySubscriptionProcedure> = undefined extends inferProcedureParams<TProcedure>["$types"]["input"] ? void | inferProcedureParams<TProcedure>["$types"]["input"] : inferProcedureParams<TProcedure>["$types"]["input"]inferSubscriptionInput<
type AppRouter = Router<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: number;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        byId: QueryProcedure<{
            input: string;
            output: {
                id: number;
                title: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        create: MutationProcedure<{
            input: {
                title: string;
                text: string;
            };
            output: {
                ...;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        onPostAdd: SubscriptionProcedure<...>;
    }>>;
}>> & DecorateCreateRouterOptions<...>
AppRouter
['post']['onPostAdd']>;
type OnPostAddInput = {
    authorId: string;
}
type OnPostAddOutput = type inferSubscriptionOutput<TProcedure extends AnySubscriptionProcedure> = TProcedure extends LegacyObservableSubscriptionProcedure<any> ? inferProcedureOutput<TProcedure> : inferAsyncIterableYield<inferProcedureOutput<TProcedure>>inferSubscriptionOutput<
type AppRouter = Router<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: number;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        byId: QueryProcedure<{
            input: string;
            output: {
                id: number;
                title: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        create: MutationProcedure<{
            input: {
                title: string;
                text: string;
            };
            output: {
                ...;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        onPostAdd: SubscriptionProcedure<...>;
    }>>;
}>> & DecorateCreateRouterOptions<...>
AppRouter
['post']['onPostAdd']>;
type OnPostAddOutput = {
    id: number;
    title: string;
    authorId: string;
}

Infer TRPCClientError types

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

client.ts
import { class TRPCClientError<TRouterOrProcedure extends InferrableClientTypes>TRPCClientError } from '@trpc/client';
import type { 
type AppRouter = Router<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: number;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        byId: QueryProcedure<{
            input: string;
            output: {
                id: number;
                title: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        create: MutationProcedure<{
            input: {
                title: string;
                text: string;
            };
            output: {
                ...;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        onPostAdd: SubscriptionProcedure<...>;
    }>>;
}>> & DecorateCreateRouterOptions<...>
AppRouter
} from './server';
import {
const trpc: TRPCClient<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: number;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        byId: QueryProcedure<{
            input: string;
            output: {
                id: number;
                title: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        create: MutationProcedure<{
            input: {
                title: string;
                text: string;
            };
            output: {
                ...;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        onPostAdd: SubscriptionProcedure<...>;
    }>>;
}>>>
trpc
} from './trpc';
export function function isTRPCClientError(cause: unknown): cause is TRPCClientError<AppRouter>isTRPCClientError( cause: unknowncause: unknown, ): cause: unknowncause is class TRPCClientError<TRouterOrProcedure extends InferrableClientTypes>TRPCClientError<
type AppRouter = Router<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: number;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        byId: QueryProcedure<{
            input: string;
            output: {
                id: number;
                title: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        create: MutationProcedure<{
            input: {
                title: string;
                text: string;
            };
            output: {
                ...;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        onPostAdd: SubscriptionProcedure<...>;
    }>>;
}>> & DecorateCreateRouterOptions<...>
AppRouter
> {
return cause: unknowncause instanceof class TRPCClientError<TRouterOrProcedure extends InferrableClientTypes>TRPCClientError; } async function function main(): Promise<void>main() { try { await
const trpc: TRPCClient<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: number;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        byId: QueryProcedure<{
            input: string;
            output: {
                id: number;
                title: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        create: MutationProcedure<{
            input: {
                title: string;
                text: string;
            };
            output: {
                ...;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        onPostAdd: SubscriptionProcedure<...>;
    }>>;
}>>>
trpc
.
post: DecoratedProcedureRecord<{
    transformer: false;
    errorShape: DefaultErrorShape;
}, DecorateCreateRouterOptions<{
    list: QueryProcedure<{
        input: void;
        output: {
            id: number;
            title: string;
        }[];
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    byId: QueryProcedure<{
        input: string;
        output: {
            id: number;
            title: string;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    create: MutationProcedure<{
        input: {
            title: string;
            text: string;
        };
        output: {
            ...;
        };
        meta: object;
        errorShape: DefaultErrorShape;
    }>;
    onPostAdd: SubscriptionProcedure<...>;
}>>
post
.
byId: {
    query: Resolver<{
        input: string;
        output: {
            id: number;
            title: string;
        };
        errorShape: DefaultErrorShape;
        transformer: false;
    }>;
}
byId
.
query: (input: string, opts?: TRPCProcedureOptions) => TRPCTaggedPromise<{
    id: number;
    title: string;
}, DefaultErrorShape>
query
('1');
} catch (function (local var) cause: unknowncause) { if (function isTRPCClientError(cause: unknown): cause is TRPCClientError<AppRouter>isTRPCClientError(function (local var) cause: unknowncause)) { // `cause` is now typed as your router's `TRPCClientError` var console: Consoleconsole.Console.log(...data: any[]): voidlog('data',
function (local var) cause: TRPCClientError<BuiltRouter<{
    ctx: object;
    meta: object;
    errorShape: DefaultErrorShape;
    transformer: false;
}, DecorateCreateRouterOptions<{
    post: BuiltRouter<{
        ctx: object;
        meta: object;
        errorShape: DefaultErrorShape;
        transformer: false;
    }, DecorateCreateRouterOptions<{
        list: QueryProcedure<{
            input: void;
            output: {
                id: number;
                title: string;
            }[];
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        byId: QueryProcedure<{
            input: string;
            output: {
                id: number;
                title: string;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        create: MutationProcedure<{
            input: {
                title: string;
                text: string;
            };
            output: {
                ...;
            };
            meta: object;
            errorShape: DefaultErrorShape;
        }>;
        onPostAdd: SubscriptionProcedure<...>;
    }>>;
}>>>
cause
.data);
TRPCClientError<BuiltRouter<{ ctx: object; meta: object; errorShape: DefaultErrorShape; transformer: false; }, DecorateCreateRouterOptions<{ post: BuiltRouter<{ ctx: object; meta: object; errorShape: DefaultErrorShape; transformer: false; }, DecorateCreateRouterOptions<...>>; }>>>.data: Maybe<DefaultErrorData>
} else { // [...] } } } function main(): Promise<void>main();