Serializers
Plain JSON by default; danSON or superjson-style serializers keep Dates, Maps and files, and client types follow.
On this page
The serializer turns inputs and outputs into JSON on the wire. The default is plain JSON. To keep more types, pass the same serializer to the handler and to every link:
| Serializer | Keeps |
|---|---|
jsonSerializer, the default | plain JSON |
createSerializer(), danSON | Date, Map, Set, bigint, undefined, URL, files, … |
createSyncSerializer(superjson) | what the transformer knows (superjson, devalue, your own) |
Every serializer streams deferred values: a procedure can return promises, generators and ReadableStreams at any depth, and each value goes through the serializer as it settles.
Choosing one
The serializer lives on the handler and the links, not on initTrpc:
import { function createSerializer(opts?: SerializerOptions): SerializercreateSerializer } from '@trpc12/trpc/serializer';
export const const serializer: Serializer<DansonForm>serializer = function createSerializer(opts?: SerializerOptions): SerializercreateSerializer();
createFetchHandler<{
health: Procedure<{
type: "query";
ctx: {};
meta: {};
input: undefined;
output: string;
errors: never;
services: never;
}>;
}, undefined>(opts: FetchHandlerOptions<{
health: Procedure<{
type: "query";
ctx: {};
meta: {};
input: undefined;
output: string;
errors: never;
services: never;
}>;
}, undefined>): FetchHandler<undefined>
createFetchHandler({ BaseHandlerOptions<{ health: Procedure<{ type: "query"; ctx: {}; meta: {}; input: undefined; output: string; errors: never; services: never; }>; }>.router: {
health: Procedure<{
type: "query";
ctx: {};
meta: {};
input: undefined;
output: string;
errors: never;
services: never;
}>;
}
router, SerializerOption.serializer?: AnySerializer | undefinedserializer });
const const client: TrpcClient<{
health: Procedure<{
type: "query";
ctx: {};
meta: {};
input: undefined;
output: string;
errors: never;
services: never;
}>;
}, {}, undefined, LinksTypes<readonly [TrpcLink<{
form: DansonForm;
provides: "response";
}, any>]>>
client = createTrpcClient<RouterType<{
health: Procedure<{
type: "query";
ctx: {};
meta: {};
input: undefined;
output: string;
errors: never;
services: never;
}>;
}>, readonly [TrpcLink<{
form: DansonForm;
provides: "response";
}, any>]>(opts: TypedClientOptions<RouterType<{
health: Procedure<{
type: "query";
ctx: {};
meta: {};
input: undefined;
output: string;
errors: never;
services: never;
}>;
}>, readonly [TrpcLink<{
form: DansonForm;
provides: "response";
}, any>]>): TrpcClient<{
health: Procedure<{
type: "query";
ctx: {};
meta: {};
input: undefined;
output: string;
errors: never;
services: never;
}>;
}, {}, undefined, LinksTypes<...>>
createTrpcClient({
TypedClientOptions<RouterType<{ health: Procedure<{ type: "query"; ctx: {}; meta: {}; input: undefined; output: string; errors: never; services: never; }>; }>, readonly [TrpcLink<{ form: DansonForm; provides: "response"; }, any>]>.router: RouterType<{
health: Procedure<{
type: "query";
ctx: {};
meta: {};
input: undefined;
output: string;
errors: never;
services: never;
}>;
}>
router: routerType<{
health: Procedure<{
type: "query";
ctx: {};
meta: {};
input: undefined;
output: string;
errors: never;
services: never;
}>;
}>(): RouterType<{
health: Procedure<{
type: "query";
ctx: {};
meta: {};
input: undefined;
output: string;
errors: never;
services: never;
}>;
}>
routerType<type AppRouter = {
health: Procedure<{
type: "query";
ctx: {};
meta: {};
input: undefined;
output: string;
errors: never;
services: never;
}>;
}
AppRouter>(),
TypedClientOptions<RouterType<{ health: Procedure<{ type: "query"; ctx: {}; meta: {}; input: undefined; output: string; errors: never; services: never; }>; }>, readonly [TrpcLink<{ form: DansonForm; provides: "response"; }, any>]>.links: readonly [TrpcLink<{
form: DansonForm;
provides: "response";
}, any>]
links: [httpLink<{
url: string;
serializer: Serializer<DansonForm>;
}>(opts: {
url: string;
serializer: Serializer<DansonForm>;
}): TrpcLink<{
form: DansonForm;
provides: "response";
}, any>
httpLink({ url: stringurl, serializer: Serializer<DansonForm>serializer })],
});wsLink and localLink take serializer the same way. With superjson or devalue, list the types the transformer rebuilds:
export const const serializer: Serializer<SyncForm<bigint | Date | Map<any, any> | Set<any> | undefined>>serializer = createSyncSerializer<bigint | Date | Map<any, any> | Set<any> | undefined>(transformer: SyncTransformer, opts?: SyncSerializerOptions): Serializer<SyncForm<bigint | Date | Map<any, any> | Set<any> | undefined>>createSyncSerializer<
Date | interface Map<K, V>Map<any, any> | interface Set<T>Set<any> | bigint | undefined
>(class superjsonsuperjson);
// devalue: createSyncSerializer({ serialize: devalue.stringify, deserialize: devalue.parse })If the two ends disagree, calls fail with UNSUPPORTED_PROTOCOL, with a message naming both serializers. Over HTTP the handler names its serializer in the trpc-serializer response header and httpLink checks it, after the server ran the call. wsLink names its own in the connection's init message: the server answers with its own and runs none of that connection's calls on a mismatch.
Client types follow the link
The first link in the chain that has a serializer types the results. A type the serializer doesn't keep arrives in its JSON form, and the client's types say so:
import { function createTrpcClient<TSource, const TLinks extends ReadonlyArray<TrpcLink<any, RouterOf<TSource>>>>(opts: TypedClientOptions<TSource, TLinks> & DuplicateSwitchCheck<TLinks> & UnmetNeedCheck<TLinks>): TrpcClient<RouterOf<TSource>, LinksContext<TLinks>, undefined, LinksTypes<TLinks>>createTrpcClient, function httpLink<TOpts extends HttpLinkOptions>(opts: TOpts): TrpcLink<HttpLinkDecl<TOpts>>httpLink, function routerType<TRouter>(): RouterType<TRouter>routerType } from '@trpc12/trpc/client';
import { function createSerializer(opts?: SerializerOptions): SerializercreateSerializer } from '@trpc12/trpc/serializer';
const const router: {
getPost: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: {
at: Date;
tags: Set<string>;
draft: undefined;
};
errors: never;
services: never;
}>;
}
router = {
getPost: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: {
at: Date;
tags: Set<string>;
draft: undefined;
};
errors: never;
services: never;
}>
getPost: const t: TrpcRoot<Context, {}, RootDef<Context, {}>>t.TrpcRoot<Context, {}, RootDef<Context, {}>>.procedure: ProcedureBuilder<RootDef<Context, {}>>procedure.ProcedureBuilder<RootDef<Context, {}>>.query<{
at: Date;
tags: Set<string>;
draft: undefined;
}>(resolver: (opts: ResolverOpts<RootDef<Context, {}>>) => {
at: Date;
tags: Set<string>;
draft: undefined;
}): Procedure<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: {
at: Date;
tags: Set<string>;
draft: undefined;
};
errors: never;
services: never;
}>
query(() => ({
at: Dateat: new var Date: DateConstructor
new () => Date (+3 overloads)
Date(),
tags: Set<string>tags: new var Set: SetConstructor
new <string>(iterable?: Iterable<string> | null | undefined) => Set<string> (+1 overload)
Set(['a']),
draft: undefineddraft: var undefinedundefined,
})),
};
const const json: TrpcClient<{
getPost: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: {
at: Date;
tags: Set<string>;
draft: undefined;
};
errors: never;
services: never;
}>;
}, {}, undefined, LinksTypes<readonly [TrpcLink<{
form: JsonForm;
provides: "response";
}, any>]>>
json = createTrpcClient<RouterType<{
getPost: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: {
at: Date;
tags: Set<string>;
draft: undefined;
};
errors: never;
services: never;
}>;
}>, readonly [TrpcLink<{
form: JsonForm;
provides: "response";
}, any>]>(opts: TypedClientOptions<RouterType<{
getPost: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: {
at: Date;
tags: Set<string>;
draft: undefined;
};
errors: never;
services: never;
}>;
}>, readonly [TrpcLink<{
form: JsonForm;
provides: "response";
}, any>]>): TrpcClient<...>
createTrpcClient({
TypedClientOptions<RouterType<{ getPost: Procedure<{ type: "query"; ctx: Context; meta: {}; input: undefined; output: { at: Date; tags: Set<string>; draft: undefined; }; errors: never; services: never; }>; }>, readonly [...]>.router: RouterType<{
getPost: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: {
at: Date;
tags: Set<string>;
draft: undefined;
};
errors: never;
services: never;
}>;
}>
router: routerType<{
getPost: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: {
at: Date;
tags: Set<string>;
draft: undefined;
};
errors: never;
services: never;
}>;
}>(): RouterType<{
getPost: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: {
at: Date;
tags: Set<string>;
draft: undefined;
};
errors: never;
services: never;
}>;
}>
routerType<typeof const router: {
getPost: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: {
at: Date;
tags: Set<string>;
draft: undefined;
};
errors: never;
services: never;
}>;
}
router>(),
TypedClientOptions<RouterType<{ getPost: Procedure<{ type: "query"; ctx: Context; meta: {}; input: undefined; output: { at: Date; tags: Set<string>; draft: undefined; }; errors: never; services: never; }>; }>, readonly [...]>.links: readonly [TrpcLink<{
form: JsonForm;
provides: "response";
}, any>]
links: [httpLink<{
url: string;
}>(opts: {
url: string;
}): TrpcLink<{
form: JsonForm;
provides: "response";
}, any>
httpLink({ url: stringurl: '/trpc' })],
});
const plain = await const json: TrpcClient<{
getPost: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: {
at: Date;
tags: Set<string>;
draft: undefined;
};
errors: never;
services: never;
}>;
}, {}, undefined, LinksTypes<readonly [TrpcLink<{
form: JsonForm;
provides: "response";
}, any>]>>
json.getPost: {
query(input?: undefined, opts?: CallOptions<{}> | undefined): TrpcPromise<{
at: string;
tags: Record<string, never>;
}, CallError<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: {
at: Date;
tags: Set<string>;
draft: undefined;
};
errors: never;
services: never;
}, JsonForm, never>>;
}
getPost.function query(input?: undefined, opts?: CallOptions<{}> | undefined): TrpcPromise<{
at: string;
tags: Record<string, never>;
}, CallError<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: {
at: Date;
tags: Set<string>;
draft: undefined;
};
errors: never;
services: never;
}, JsonForm, never>>
query();
const const danson: TrpcClient<{
getPost: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: {
at: Date;
tags: Set<string>;
draft: undefined;
};
errors: never;
services: never;
}>;
}, {}, undefined, LinksTypes<readonly [TrpcLink<{
form: DansonForm;
provides: "response";
}, any>]>>
danson = createTrpcClient<RouterType<{
getPost: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: {
at: Date;
tags: Set<string>;
draft: undefined;
};
errors: never;
services: never;
}>;
}>, readonly [TrpcLink<{
form: DansonForm;
provides: "response";
}, any>]>(opts: TypedClientOptions<RouterType<{
getPost: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: {
at: Date;
tags: Set<string>;
draft: undefined;
};
errors: never;
services: never;
}>;
}>, readonly [TrpcLink<{
form: DansonForm;
provides: "response";
}, any>]>): TrpcClient<...>
createTrpcClient({
TypedClientOptions<RouterType<{ getPost: Procedure<{ type: "query"; ctx: Context; meta: {}; input: undefined; output: { at: Date; tags: Set<string>; draft: undefined; }; errors: never; services: never; }>; }>, readonly [...]>.router: RouterType<{
getPost: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: {
at: Date;
tags: Set<string>;
draft: undefined;
};
errors: never;
services: never;
}>;
}>
router: routerType<{
getPost: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: {
at: Date;
tags: Set<string>;
draft: undefined;
};
errors: never;
services: never;
}>;
}>(): RouterType<{
getPost: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: {
at: Date;
tags: Set<string>;
draft: undefined;
};
errors: never;
services: never;
}>;
}>
routerType<typeof const router: {
getPost: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: {
at: Date;
tags: Set<string>;
draft: undefined;
};
errors: never;
services: never;
}>;
}
router>(),
TypedClientOptions<RouterType<{ getPost: Procedure<{ type: "query"; ctx: Context; meta: {}; input: undefined; output: { at: Date; tags: Set<string>; draft: undefined; }; errors: never; services: never; }>; }>, readonly [...]>.links: readonly [TrpcLink<{
form: DansonForm;
provides: "response";
}, any>]
links: [httpLink<{
url: string;
serializer: Serializer<DansonForm>;
}>(opts: {
url: string;
serializer: Serializer<DansonForm>;
}): TrpcLink<{
form: DansonForm;
provides: "response";
}, any>
httpLink({ url: stringurl: '/trpc', serializer: Serializer<DansonForm>serializer: function createSerializer(opts?: SerializerOptions): SerializercreateSerializer() })],
});
const rich = await const danson: TrpcClient<{
getPost: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: {
at: Date;
tags: Set<string>;
draft: undefined;
};
errors: never;
services: never;
}>;
}, {}, undefined, LinksTypes<readonly [TrpcLink<{
form: DansonForm;
provides: "response";
}, any>]>>
danson.getPost: {
query(input?: undefined, opts?: CallOptions<{}> | undefined): TrpcPromise<{
at: Date;
tags: Set<string>;
draft: undefined;
}, CallError<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: {
at: Date;
tags: Set<string>;
draft: undefined;
};
errors: never;
services: never;
}, DansonForm, never>>;
}
getPost.function query(input?: undefined, opts?: CallOptions<{}> | undefined): TrpcPromise<{
at: Date;
tags: Set<string>;
draft: undefined;
}, CallError<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: {
at: Date;
tags: Set<string>;
draft: undefined;
};
errors: never;
services: never;
}, DansonForm, never>>
query();Date (and anything with toJSON) becomes what toJSON returns, Map, Set and other objects without own keys become {}, undefined keys are dropped and undefined array items become null. Types that are already JSON are kept as written, so recursive and branded JSON types survive. JsonOf<T, Keeps> is that transform, for your own types.
A typed error's data goes through the same serializer: new TrpcError({ code: 'EXPIRED', data: { at: new Date() } }) reaches a plain-JSON client as data: { at: string }.
In-process callers (createRouterClient, createTrpcRsc, localLink({ serializer: false })) pass values by reference, so they keep native types whatever the serializer.
Files
A root File or Blob output of an unbatched HTTP call is the response body, with any serializer. On a batching chain, plain JSON can't batch it, so such calls take { batch: false } (a type error otherwise). Files anywhere else, and files in inputs, need danSON; the other serializers fail before sending.
Query URLs
Query inputs go in the URL as ?input=<JSON>, with object keys sorted (array order is kept), so equal inputs make the same URL and hit the same HTTP cache entry. A serializer that makes refs (danSON's $n markers) adds &refs=. Long inputs fall back to POST (Links).
Custom types with danSON
const const decimal: CustomType<Decimal, string>decimal: interface CustomType<T, TSerialized = unknown>CustomType<class DecimalDecimal, string> = {
CustomType<Decimal, string>.is: (value: unknown) => value is Decimalis: (v: unknownv) => v: unknownv instanceof class DecimalDecimal,
CustomType<Decimal, string>.serialize: (value: Decimal) => stringserialize: (v: Decimalv) => v: Decimalv.Object.toString(): stringtoString(),
CustomType<Decimal, string>.deserialize: (value: string) => Decimaldeserialize: (s: strings) => new constructor Decimal(value: string): DecimalDecimal(s: strings),
};
export const const serializer: Serializer<DansonForm>serializer = function createSerializer(opts?: SerializerOptions): SerializercreateSerializer({ SerializerOptions.types?: Record<string, CustomType<any, any>> | undefinedtypes: { type Decimal: CustomType<Decimal, string>Decimal: const decimal: CustomType<Decimal, string>decimal } });The examples/media-pipeline app keeps a Money class this way, and with superjson's registerCustom on a second endpoint, in query URLs and outputs.
Hydration
hydrationOptions({ client }) serializes TanStack Query data with the client's serializer (the first link that has one), so server-rendered data hydrates with the same types the client sees. Type the query context from the client, and it takes the links' form too:
const const makeClient: () => TrpcClient<{
post: {
byId: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", {
id: string;
}> | SchemaValidationError<ZodObject<{
id: ZodString;
}, $strip>>;
services: never;
}>;
list: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: Post[];
errors: never;
services: never;
}>;
create: Procedure<{
type: "mutation";
ctx: Context;
meta: {};
input: {
title: string;
};
output: Post;
errors: TrpcError<...> | SchemaValidationError<...>;
services: never;
}>;
};
}, {}, undefined, LinksTypes<...>>
makeClient = () =>
createTrpcClient<RouterType<{
post: {
byId: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", {
id: string;
}> | SchemaValidationError<ZodObject<{
id: ZodString;
}, $strip>>;
services: never;
}>;
list: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: Post[];
errors: never;
services: never;
}>;
create: Procedure<{
type: "mutation";
ctx: Context;
meta: {};
input: {
title: string;
};
output: Post;
errors: TrpcError<...> | SchemaValidationError<...>;
services: never;
}>;
};
}>, readonly [...]>(opts: TypedClientOptions<...>): TrpcClient<...>
createTrpcClient({
TypedClientOptions<RouterType<{ post: { byId: Procedure<{ type: "query"; ctx: Context; meta: {}; input: { id: string; }; output: Post; errors: TrpcError<"NOT_FOUND", { id: string; }> | SchemaValidationError<ZodObject<{ id: ZodString; }, $strip>>; services: never; }>; list: Procedure<...>; create: Procedure<...>; }; }>, readonly [...]>.router: RouterType<{
post: {
byId: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", {
id: string;
}> | SchemaValidationError<ZodObject<{
id: ZodString;
}, $strip>>;
services: never;
}>;
list: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: Post[];
errors: never;
services: never;
}>;
create: Procedure<{
type: "mutation";
ctx: Context;
meta: {};
input: {
title: string;
};
output: Post;
errors: TrpcError<...> | SchemaValidationError<...>;
services: never;
}>;
};
}>
router: routerType<{
post: {
byId: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", {
id: string;
}> | SchemaValidationError<ZodObject<{
id: ZodString;
}, $strip>>;
services: never;
}>;
list: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: Post[];
errors: never;
services: never;
}>;
create: Procedure<{
type: "mutation";
ctx: Context;
meta: {};
input: {
title: string;
};
output: Post;
errors: TrpcError<...> | SchemaValidationError<...>;
services: never;
}>;
};
}>(): RouterType<...>
routerType<type AppRouter = {
post: {
byId: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", {
id: string;
}> | SchemaValidationError<ZodObject<{
id: ZodString;
}, $strip>>;
services: never;
}>;
list: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: Post[];
errors: never;
services: never;
}>;
create: Procedure<{
type: "mutation";
ctx: Context;
meta: {};
input: {
title: string;
};
output: Post;
errors: TrpcError<...> | SchemaValidationError<...>;
services: never;
}>;
};
}
AppRouter>(),
TypedClientOptions<RouterType<{ post: { byId: Procedure<{ type: "query"; ctx: Context; meta: {}; input: { id: string; }; output: Post; errors: TrpcError<"NOT_FOUND", { id: string; }> | SchemaValidationError<ZodObject<{ id: ZodString; }, $strip>>; services: never; }>; list: Procedure<...>; create: Procedure<...>; }; }>, readonly [...]>.links: readonly [TrpcLink<{
form: DansonForm;
provides: "response";
}, any>]
links: [httpLink<{
url: string;
serializer: Serializer<DansonForm>;
}>(opts: {
url: string;
serializer: Serializer<DansonForm>;
}): TrpcLink<{
form: DansonForm;
provides: "response";
}, any>
httpLink({ url: stringurl, serializer: Serializer<DansonForm>serializer })],
});
export const [const TrpcProvider: (props: TrpcProviderProps<{
post: {
byId: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", {
id: string;
}> | SchemaValidationError<ZodObject<{
id: ZodString;
}, $strip>>;
services: never;
}>;
list: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: Post[];
errors: never;
services: never;
}>;
create: Procedure<{
type: "mutation";
ctx: Context;
meta: {};
input: {
title: string;
};
output: Post;
errors: TrpcError<...> | SchemaValidationError<...>;
services: never;
}>;
};
}, {}, LinksTypes<...>>) => React.ReactNode
TrpcProvider, const useTrpc: () => TrpcQueryUtilsFor<{
post: {
byId: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", {
id: string;
}> | SchemaValidationError<ZodObject<{
id: ZodString;
}, $strip>>;
services: never;
}>;
list: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: Post[];
errors: never;
services: never;
}>;
create: Procedure<{
type: "mutation";
ctx: Context;
meta: {};
input: {
title: string;
};
output: Post;
errors: TrpcError<...> | SchemaValidationError<...>;
services: never;
}>;
};
}, {}, LinksTypes<...>>
useTrpc] = createTrpcContext<() => TrpcClient<{
post: {
byId: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", {
id: string;
}> | SchemaValidationError<ZodObject<{
id: ZodString;
}, $strip>>;
services: never;
}>;
list: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: Post[];
errors: never;
services: never;
}>;
create: Procedure<{
type: "mutation";
ctx: Context;
meta: {};
input: {
title: string;
};
output: Post;
errors: TrpcError<...> | SchemaValidationError<...>;
services: never;
}>;
};
}, {}, undefined, LinksTypes<...>>>(opts?: TrpcContextOptions): TrpcReactContext<...>
createTrpcContext<typeof const makeClient: () => TrpcClient<{
post: {
byId: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", {
id: string;
}> | SchemaValidationError<ZodObject<{
id: ZodString;
}, $strip>>;
services: never;
}>;
list: Procedure<{
type: "query";
ctx: Context;
meta: {};
input: undefined;
output: Post[];
errors: never;
services: never;
}>;
create: Procedure<{
type: "mutation";
ctx: Context;
meta: {};
input: {
title: string;
};
output: Post;
errors: TrpcError<...> | SchemaValidationError<...>;
services: never;
}>;
};
}, {}, undefined, LinksTypes<...>>
makeClient>();A router type alone (createTrpcContext<AppRouter>()) has no links, so it types the default JSON form.
See Hydration.