T
tRPC

❓-help

Losing the type between the client and server

VVolks10/12/2022
Hello everyone, I am new to tRPC and the magic of types in typescript so I am looking for ideas as to what is happening, the client is receiving any type instead of a string I doubt this is a bug, but I have no idea where to go for. This is on the client
(property) onSuccess?: ((data: {
id: any;
exists: any;
name: any;
email: string;
}, variables: {
provider?: any;
presignupEmail?: string | undefined;
email: string;
userID: string;
}, context: unknown) => unknown) | undefined
(property) onSuccess?: ((data: {
id: any;
exists: any;
name: any;
email: string;
}, variables: {
provider?: any;
presignupEmail?: string | undefined;
email: string;
userID: string;
}, context: unknown) => unknown) | undefined
And this is on the server
(method) ProcedureBuilder<{ _config: RootConfig<{ ctx: { user?: undefined; } | { user: { uid: string; email: string; }; }; meta: {}; errorShape: DefaultErrorShape; transformer: CombinedDataTransformer; }>; ... 5 more ...; _output_out: typeof unsetMarker; }>.mutation<{
id: string;
exists: boolean;
name: string | undefined;
email: string;
}>(resolver: (opts: ResolveOptions<{
_config: RootConfig<{
ctx: {
user?: undefined;
} | {
user: {
uid: string;
email: string;
};
};
meta: {};
errorShape: DefaultErrorShape;
transformer: CombinedDataTransformer;
}>;
... 5 more ...;
_output_out: typeof unsetMarker;
}>) => MaybePromise<...>): BuildProcedure<...>
Mutation procedure
(method) ProcedureBuilder<{ _config: RootConfig<{ ctx: { user?: undefined; } | { user: { uid: string; email: string; }; }; meta: {}; errorShape: DefaultErrorShape; transformer: CombinedDataTransformer; }>; ... 5 more ...; _output_out: typeof unsetMarker; }>.mutation<{
id: string;
exists: boolean;
name: string | undefined;
email: string;
}>(resolver: (opts: ResolveOptions<{
_config: RootConfig<{
ctx: {
user?: undefined;
} | {
user: {
uid: string;
email: string;
};
};
meta: {};
errorShape: DefaultErrorShape;
transformer: CombinedDataTransformer;
}>;
... 5 more ...;
_output_out: typeof unsetMarker;
}>) => MaybePromise<...>): BuildProcedure<...>
Mutation procedure
Jjulius10/12/2022
Do you have strict mode? Are you using any data transformers?
VVolks10/14/2022
Hey @julius, I am using strict mode and I am using superjson. I am currently debugging on a reproducable repo first, but with a stripped down setup the types are working, so I am super confused at the moment Do you maybe have any pointers at the top of your head that can break types between projects. I basically have a monorepo
apps/
- backend with trpc that exports app router
- nextjs site that imports the app router
apps/
- backend with trpc that exports app router
- nextjs site that imports the app router
I just import the type from ../apps/backend/src/trpc.ts I'll keep debugging and close this if I find the culprit
Jjulius10/14/2022
Not really, is the repo public?
VVolks10/18/2022
I have a minimal repository that closely mimics my real project which is unfortunately commercial and private, but I cannot for the life of me replicate the issue I am having in the real project @julius For example
export const sessionContext = async ({
req,
}: NodeHTTPCreateContextFnOptions<IncomingMessage, ServerResponse>) => {
try {
if (
req.headers.authorization &&
req.headers.authorization.split(" ")[0] === "Bearer"
) {
const token = req.headers.authorization.split(" ")[1] as string;
const decodedToken = await firebaseAdmin.auth().verifyIdToken(token);

if (!decodedToken.email) {
return {};
}

return {
user: {
uid: decodedToken.uid,
email: decodedToken.email,
},
};
}
return {};
} catch (error) {
return {};
}
};

export type Context = inferAsyncReturnType<typeof sessionContext>;
export const sessionContext = async ({
req,
}: NodeHTTPCreateContextFnOptions<IncomingMessage, ServerResponse>) => {
try {
if (
req.headers.authorization &&
req.headers.authorization.split(" ")[0] === "Bearer"
) {
const token = req.headers.authorization.split(" ")[1] as string;
const decodedToken = await firebaseAdmin.auth().verifyIdToken(token);

if (!decodedToken.email) {
return {};
}

return {
user: {
uid: decodedToken.uid,
email: decodedToken.email,
},
};
}
return {};
} catch (error) {
return {};
}
};

export type Context = inferAsyncReturnType<typeof sessionContext>;
In my main project it has any types like displayed bellow but in my demo project it correctly has the uid and email as strings
(alias) type AppRouter = Router<RouterDef<RootConfig<{
ctx: {
user?: undefined;
} | {
user: {
uid: any;
email: any;
};
};
}>, {
...;
}, {
...;
}>> & {
...;
}
(alias) type AppRouter = Router<RouterDef<RootConfig<{
ctx: {
user?: undefined;
} | {
user: {
uid: any;
email: any;
};
};
}>, {
...;
}, {
...;
}>> & {
...;
}
So I thought that the types might be incorrect all together but if I do
export const sessionContext = async ({
req,
}: NodeHTTPCreateContextFnOptions<IncomingMessage, ServerResponse>) => {
return {
user: {
uid: "test",
email: "test",
},
};
};

export type Context = inferAsyncReturnType<typeof sessionContext>;
export const sessionContext = async ({
req,
}: NodeHTTPCreateContextFnOptions<IncomingMessage, ServerResponse>) => {
return {
user: {
uid: "test",
email: "test",
},
};
};

export type Context = inferAsyncReturnType<typeof sessionContext>;
It gets inferred to
(alias) type AppRouter = Router<RouterDef<RootConfig<{
ctx: {
user: {
uid: string;
email: string;
};
};
}
(alias) type AppRouter = Router<RouterDef<RootConfig<{
ctx: {
user: {
uid: string;
email: string;
};
};
}
The type is correct on the server but gets inferred to any in the client But as you can see the types do get across Just some are any I have absolutely no clue as to what is happening Also the inferred type of my mutation has the same issue
type test = {
id: any;
exists: any;
name: any;
email: string;
}
type test = {
id: any;
exists: any;
name: any;
email: string;
}
But on the server the types are all okay
(method) ProcedureBuilder<{ _config: RootConfig<{ ctx: { user?: undefined; } | { user: { uid: string; email: string; }; }; meta: {}; errorShape: DefaultErrorShape; transformer: CombinedDataTransformer; }>; ... 5 more ...; _output_out: typeof unsetMarker; }>.mutation<{
id: string;
exists: boolean;
name: string | undefined;
email: string;
}>(resolver: (opts: ResolveOptions<{
(method) ProcedureBuilder<{ _config: RootConfig<{ ctx: { user?: undefined; } | { user: { uid: string; email: string; }; }; meta: {}; errorShape: DefaultErrorShape; transformer: CombinedDataTransformer; }>; ... 5 more ...; _output_out: typeof unsetMarker; }>.mutation<{
id: string;
exists: boolean;
name: string | undefined;
email: string;
}>(resolver: (opts: ResolveOptions<{
Jjulius10/18/2022
might be invalid tsconfig? or do you use the same in the repro?
VVolks10/18/2022
Both are the same, strict mode is on But the types are getting through to the client, just for some reason some types are lost and inferred to any Thats why I am super confused
Jjulius10/18/2022
yea if you cant provide a repro i really cant help you since ive never seen this before
VVolks10/21/2022
Yeah I'll try to get it reproduced and push it to gh Hey @julius, tried my best to create a simple reproducible repository that reflects my issue. I added a readme that clarifies the issue further, here is the repo https://github.com/Nikola-Milovic/monorepo-trpc-issue I know this is a tall ask to check out but thank you nonetheless Inside packages/config are the tsconfig files and they all inherit from the base.json which defines the strict: true

Looking for more? Join the community!

Recommended Posts
Mobile app with tRPCWhat's the suggested way of working with tRPC when it comes to mobile apps? How do you ensure that yHow to use trpc react hooks from an external data sourceHi, I have a monorepo, nextjs and keystone cms. The cms has trpc running, and I managed to get it coNextJS & Keystone CMS, issues when connecting both in a monorepoHello everyone, so I have a monorepo with NextJS and keystone cms, both are running trpc v10beta.15Best practices for implementing an offline applicationHey there! I'm building a full stack react-native app with Expo and a tRPC backend. I'd like for thisomehow when move typed function out of the router files, frontend infer type to be any ?this is inferred corrected since they are in the same file. ``` getX: t.procedure.query(() => { retBig companies that use tRPC?Some of my fellow colleagues were wondering if there are any big companies that use tRPC and how matMigrating to V10 from V9If someone has some ideas on what I might have screwed up when trying to bump tRPC for this public sAuthentication broke after bump to v10 from v9Anyone that has any suggestions on what might have caused this? I get the following error when tryiShow a spinner when any mutation is loading?Looking to show an activity spinner in the header of our application whenever a mutation is in flighSharing schemas between server and clientIn a typical nextJs setup, what is the idiomatic way to share zod schemas between frontend and backev10 Migration interop, router doesnt have attributesHi, i've tried to migrate like stated in the docs, these are my routers. Question: Shouldn't appRoutRecommended file structure for next.js?Hey all - using tRPC heavily with next.js and it's great. Our main `[trpc].ts` file is getting huge Unhandled Runtime ErrorTRPCClientErrorCall Stack Function.from node_modules\@trpc\client\dist\TRPCClientError-09b8a26b.esm.js (57:0) transSharing middleware between TRPC serversWe currently have *microservices* REST API's on Cloudflare Workers and I'm thinking about moving thiIs `trpc.withTRPC` for Next supposed to work with pages or only `_app`?I'd love to only have TRPC mount on certain pages of my Next.js app. Is this currently supported?Are there any example of subscriptions working with react native ?queries and mutations are working pretty well with react native, I'm unable however to get subscriptRecommended way to prefetch client-sideIn react-query, you can do ``` queryClient.prefetchQuery(['todos', input], queryFn) ``` In trpc, IRevalidate API route from procedureHi, is there a way to revalidate a statically generated page from a trpc procedure? https://nextjs.Modifying payload client-side before cachingSay I have a payload that includes something like `category_id` in each of the items returned e.g.: Response headersIs it possible to modify the response headers from server to client?