T
TanStack•3w ago
ratty-blush

Wrong type inference from beforeLoad/loader when using complex objects in return

I've added all the necessary types and declarations, started the fresh new project. I want to prefetch the product from an api and i have all the necessary types infered. Here's an example of the code:
export const Route = createFileRoute(
'/$locale/_layout/(main)/_main/product/$handle'
)({
beforeLoad: async ({ params: { handle }, context: { region } }) => {
const product = await queryClient.fetchQuery(
getProductByHandleQueryOptions({ handle, region_id: region.id })
);

if (!product) {
throw notFound({
routeId: Route.id,
data: { handle },
});
}

return { product };
},
component: ProductTemplate,
});
export const Route = createFileRoute(
'/$locale/_layout/(main)/_main/product/$handle'
)({
beforeLoad: async ({ params: { handle }, context: { region } }) => {
const product = await queryClient.fetchQuery(
getProductByHandleQueryOptions({ handle, region_id: region.id })
);

if (!product) {
throw notFound({
routeId: Route.id,
data: { handle },
});
}

return { product };
},
component: ProductTemplate,
});
7 Replies
ratty-blush
ratty-blushOP•3w ago
and when returning the whole product object i get this error (need to split this into multiple messages):
Type '({ params: { handle }, context: { region } }: BeforeLoadContextOptions<Register, Route<Register, Route<Register, Route<Register, RootRoute<Register, undefined, MyRouterContext, AnyContext, ... 7 more ..., undefined>, ... 15 more ..., undefined>, ... 15 more ..., undefined>, ... 15 more ..., undefined>, ... 5 more .....' is not assignable to type '(ctx: BeforeLoadContextOptions<Register, Route<Register, Route<Register, Route<Register, RootRoute<Register, undefined, MyRouterContext, AnyContext, ... 7 more ..., undefined>, ... 15 more ..., undefined>, ... 15 more ..., undefined>, ... 15 more ..., undefined>, ... 5 more ..., undefined>) => Promise<...>'.
Type 'Promise<{ product: StoreProduct; }>' is not assignable to type 'Promise<{ product: { collection?: { products?: ...[] | undefined; id: string; title: string; metadata: { [x: string]: {}; } | null; created_at: string; updated_at: string; handle: string; deleted_at: string | null; } | null | undefined; ... 29 more ...; deleted_at: string | null; }; }>'.
Type '{ product: StoreProduct; }' is not assignable to type '{ product: { collection?: { products?: ...[] | undefined; id: string; title: string; metadata: { [x: string]: {}; } | null; created_at: string; updated_at: string; handle: string; deleted_at: string | null; } | null | undefined; ... 29 more ...; deleted_at: string | null; }; }'.
The types of 'product.collection' are incompatible between these types.
Type '({ params: { handle }, context: { region } }: BeforeLoadContextOptions<Register, Route<Register, Route<Register, Route<Register, RootRoute<Register, undefined, MyRouterContext, AnyContext, ... 7 more ..., undefined>, ... 15 more ..., undefined>, ... 15 more ..., undefined>, ... 15 more ..., undefined>, ... 5 more .....' is not assignable to type '(ctx: BeforeLoadContextOptions<Register, Route<Register, Route<Register, Route<Register, RootRoute<Register, undefined, MyRouterContext, AnyContext, ... 7 more ..., undefined>, ... 15 more ..., undefined>, ... 15 more ..., undefined>, ... 15 more ..., undefined>, ... 5 more ..., undefined>) => Promise<...>'.
Type 'Promise<{ product: StoreProduct; }>' is not assignable to type 'Promise<{ product: { collection?: { products?: ...[] | undefined; id: string; title: string; metadata: { [x: string]: {}; } | null; created_at: string; updated_at: string; handle: string; deleted_at: string | null; } | null | undefined; ... 29 more ...; deleted_at: string | null; }; }>'.
Type '{ product: StoreProduct; }' is not assignable to type '{ product: { collection?: { products?: ...[] | undefined; id: string; title: string; metadata: { [x: string]: {}; } | null; created_at: string; updated_at: string; handle: string; deleted_at: string | null; } | null | undefined; ... 29 more ...; deleted_at: string | null; }; }'.
The types of 'product.collection' are incompatible between these types.
Type 'StoreCollection | null | undefined' is not assignable to type '{ products?: { collection?: ... | null | undefined; categories?: { products?: ...[] | undefined; parent_category: ... | null; category_children: ...[]; id: string; name: string; metadata?: { ...; } | ... 1 more ... | undefined; ... 6 more ...; parent_category_id: string | null; }[] | null | undefined; ... 28 more .....'.
Type 'StoreCollection' is not assignable to type '{ products?: { collection?: ... | null | undefined; categories?: { products?: ...[] | undefined; parent_category: ... | null; category_children: ...[]; id: string; name: string; metadata?: { ...; } | null | undefined; ... 6 more ...; parent_category_id: string | null; }[] | null | undefined; ... 28 more ...; deleted...'.
Types of property 'metadata' are incompatible.
Type 'Record<string, unknown> | null' is not assignable to type '{ [x: string]: {}; } | null'.
Type 'Record<string, unknown>' is not assignable to type '{ [x: string]: {}; }'.
'string' index signatures are incompatible.
Type 'unknown' is not assignable to type '{}'.ts(2322)
Type 'StoreCollection | null | undefined' is not assignable to type '{ products?: { collection?: ... | null | undefined; categories?: { products?: ...[] | undefined; parent_category: ... | null; category_children: ...[]; id: string; name: string; metadata?: { ...; } | ... 1 more ... | undefined; ... 6 more ...; parent_category_id: string | null; }[] | null | undefined; ... 28 more .....'.
Type 'StoreCollection' is not assignable to type '{ products?: { collection?: ... | null | undefined; categories?: { products?: ...[] | undefined; parent_category: ... | null; category_children: ...[]; id: string; name: string; metadata?: { ...; } | null | undefined; ... 6 more ...; parent_category_id: string | null; }[] | null | undefined; ... 28 more ...; deleted...'.
Types of property 'metadata' are incompatible.
Type 'Record<string, unknown> | null' is not assignable to type '{ [x: string]: {}; } | null'.
Type 'Record<string, unknown>' is not assignable to type '{ [x: string]: {}; }'.
'string' index signatures are incompatible.
Type 'unknown' is not assignable to type '{}'.ts(2322)
as for returning only title (for example) it infers the type just fine. That's why i think that there's something wrong only on some more complex types Here's an example of the type that works when being returned from the loader: https://github.com/medusajs/medusa/blob/develop/www/utils/generated/oas-output/schemas/BaseRegion.ts
export interface BaseRegion {
/**
* The region's ID.
*/
id: string;
/**
* The region's name.
*/
name: string;
/**
* The region's currency code.
*/
currency_code: string;
/**
* Whether taxes are calculated automatically in the region.
*/
automatic_taxes?: boolean;
/**
* The countries that belong to the region.
*/
countries?: BaseRegionCountry[];
/**
* The payment providers enabled in the region.
*/
payment_providers?: AdminPaymentProvider[];
/**
* Key-value pairs of custom data.
*/
metadata?: Record<string, any> | null;
/**
* The date the region was created.
*/
created_at?: string;
/**
* The date the region was updated.
*/
updated_at?: string;
}
export interface BaseRegion {
/**
* The region's ID.
*/
id: string;
/**
* The region's name.
*/
name: string;
/**
* The region's currency code.
*/
currency_code: string;
/**
* Whether taxes are calculated automatically in the region.
*/
automatic_taxes?: boolean;
/**
* The countries that belong to the region.
*/
countries?: BaseRegionCountry[];
/**
* The payment providers enabled in the region.
*/
payment_providers?: AdminPaymentProvider[];
/**
* Key-value pairs of custom data.
*/
metadata?: Record<string, any> | null;
/**
* The date the region was created.
*/
created_at?: string;
/**
* The date the region was updated.
*/
updated_at?: string;
}
and here's an example of the current one that doesn't: https://github.com/medusajs/medusa/blob/develop/www/utils/generated/oas-output/schemas/StoreProduct.ts Also, i have tried prefetching a different data (there's also metadata object inside that data), and again the same error (i'll copy last few lines only):
Type 'StoreCollection' is not assignable to type '{ products?: { collection?: ... | null | undefined; categories?: { products?: ...[] | undefined; parent_category: ... | null; category_children: ...[]; id: string; name: string; metadata?: { ...; } | null | undefined; ... 6 more ...; rank: number | null; }[] | null | undefined; ... 28 more ...; external_id: string |...'.
Types of property 'metadata' are incompatible.
Type 'Record<string, unknown> | null' is not assignable to type '{ [x: string]: {}; } | null'.
Type 'Record<string, unknown>' is not assignable to type '{ [x: string]: {}; }'.
'string' index signatures are incompatible.
Type 'unknown' is not assignable to type '{}'.ts(2322)
Type 'StoreCollection' is not assignable to type '{ products?: { collection?: ... | null | undefined; categories?: { products?: ...[] | undefined; parent_category: ... | null; category_children: ...[]; id: string; name: string; metadata?: { ...; } | null | undefined; ... 6 more ...; rank: number | null; }[] | null | undefined; ... 28 more ...; external_id: string |...'.
Types of property 'metadata' are incompatible.
Type 'Record<string, unknown> | null' is not assignable to type '{ [x: string]: {}; } | null'.
Type 'Record<string, unknown>' is not assignable to type '{ [x: string]: {}; }'.
'string' index signatures are incompatible.
Type 'unknown' is not assignable to type '{}'.ts(2322)
wise-white
wise-white•3w ago
Pretty sure the problem is the unknown types since TS Start can't confidently serialize an unknown value.
wise-white
wise-white•3w ago
yep exactly unknown could be a non serializable thing at runtime, hence the type error
ratty-blush
ratty-blushOP•3w ago
thanks for the reply. Then what would be the best course of action here? Reporting this to the package that i'm using doesn't seem right just because unknown can be and is used in many packages or should tanstack implement some kind of workaround/fix for this? I'm asking this just becase i ignored the error, typed the data myself and it works just fine, and to not use something just because tere's a type missmatch seems like a wrong thing to do
wise-white
wise-white•3w ago
The problem isn't really a type mismatch. The library you use most likely types it as unknown since it is generic and they don't know what data you have, and Tanstack Start can't assume either. That leaves you, the developer, that knows what type your data has. That said, overriding the unknown type to something concrete, is the correct way to do it.
wise-white
wise-white•2w ago
absolutely we are however looking into ways to let you opt out of this type check, on your own risk of course 😄
ratty-blush
ratty-blushOP•2w ago
haha i get it, i mean, you practically opt out by typing it on your own, it's just annoying but still works 😄

Did you find this page helpful?