T
TanStack8mo ago
like-gold

Tanstack router looses types in loader

I am developing a SPA using Tanstack router and convex.dev. The following code works and result is properly typed inside the loader function. In my route component, when I run const data = Route.useLoaderData(); the TypeScript type is any. Am I using the loader function wrong here? I've tried adding an explicit return type, but it still didn't work
export const Route = createFileRoute(
"/_app/freelance/my-applications/_layout/$applicationId",
)({
component: RouteComponent,
loader: async ({
context,
params,
}: {
context: { queryClient: QueryClient };
params: { applicationId: Id<"applications"> };
}): Promise<{
application: Application;
job: Job;
}> => {
const result = await context.queryClient.ensureQueryData(
convexQuery(api.app.applications.getApplication, {
applicationId: params.applicationId,
}),
);
if (!result?.application) {
throw new Error(
`Application with ID "${params.applicationId}" not found.`,
);
}
return result;
},
});

function RouteComponent() {
const data = Route.useLoaderData();

return (
<div>
<h1>Page</h1>
</div>
);
}
export const Route = createFileRoute(
"/_app/freelance/my-applications/_layout/$applicationId",
)({
component: RouteComponent,
loader: async ({
context,
params,
}: {
context: { queryClient: QueryClient };
params: { applicationId: Id<"applications"> };
}): Promise<{
application: Application;
job: Job;
}> => {
const result = await context.queryClient.ensureQueryData(
convexQuery(api.app.applications.getApplication, {
applicationId: params.applicationId,
}),
);
if (!result?.application) {
throw new Error(
`Application with ID "${params.applicationId}" not found.`,
);
}
return result;
},
});

function RouteComponent() {
const data = Route.useLoaderData();

return (
<div>
<h1>Page</h1>
</div>
);
}
8 Replies
harsh-harlequin
harsh-harlequin8mo ago
please provide a complete minimal example
like-gold
like-goldOP8mo ago
@Manuel Schiller What more do I need to show? I'm not sure how to give a better without including all of the Convex logic. The function getApplication returns typed data and the result variable is typed. I'm just asking how to ensure that Route.useLoaderData(); is typed Is it recommended to do something like this? And manually type the Route.useLoaderData() call?
type LoaderData = {
application: Application;
job: Job;
};

export const Route = createFileRoute(
"/_app/freelance/my-applications/_layout/$applicationId",
)({
component: RouteComponent,
loader: async ({
context,
params,
}: {
context: { queryClient: QueryClient };
params: { applicationId: Id<"applications"> };
}): Promise<LoaderData> => {
const result = await context.queryClient.ensureQueryData(
convexQuery(api.app.applications.getApplication, {
applicationId: params.applicationId,
}),
);
if (!result?.application) {
throw new Error(
`Application with ID "${params.applicationId}" not found.`,
);
}
return result;
},
});

function RouteComponent() {
const data: LoaderData = Route.useLoaderData();

return (
<div>
<h1>Page</h1>
</div>
);
}
type LoaderData = {
application: Application;
job: Job;
};

export const Route = createFileRoute(
"/_app/freelance/my-applications/_layout/$applicationId",
)({
component: RouteComponent,
loader: async ({
context,
params,
}: {
context: { queryClient: QueryClient };
params: { applicationId: Id<"applications"> };
}): Promise<LoaderData> => {
const result = await context.queryClient.ensureQueryData(
convexQuery(api.app.applications.getApplication, {
applicationId: params.applicationId,
}),
);
if (!result?.application) {
throw new Error(
`Application with ID "${params.applicationId}" not found.`,
);
}
return result;
},
});

function RouteComponent() {
const data: LoaderData = Route.useLoaderData();

return (
<div>
<h1>Page</h1>
</div>
);
}
harsh-harlequin
harsh-harlequin8mo ago
a full example would be e.g. forking an existing example from stackblitz something that can be debugged not just some snippet
like-gold
like-goldOP8mo ago
ok But should Tanstack router handle the return type of Route.useLoaderData automatically? I'm not sure what's possible and there's not too much on the docs
harsh-harlequin
harsh-harlequin8mo ago
yes it should there must be something wrong in your setup
like-gold
like-goldOP8mo ago
Ok that's good to know @Manuel Schiller Ok. I think it might have been because I was missing this code. Is this required for some type inferance?
declare module "@tanstack/react-router" {
interface Register {
router: typeof router;
}
}
declare module "@tanstack/react-router" {
interface Register {
router: typeof router;
}
}
harsh-harlequin
harsh-harlequin8mo ago
absolutely which is why I asked for a complete example it would have shown that this was missing
like-gold
like-goldOP8mo ago
Ok I used https://github.com/get-convex/convex-saas as a base so I'll open a PR to fix it on their template
GitHub
GitHub - get-convex/convex-saas: A production-ready Convex Stack fo...
A production-ready Convex Stack for your next SaaS application with Convex Auth, Stripe, TanStack, Resend, Tailwindcss, and shadcn. - get-convex/convex-saas

Did you find this page helpful?