Typesafe wrapper around load functions #9180
-
I have some common logic that should run at the beginning of every load function (in my case, only on the server). The concrete example is authorization and I want to enforce permission checking on any route. The final solution should look something like that: import type { PageServerLoad } from './$types.js'
export const load: PageServerLoad = serverRoute(permission, async (event) => {
[...]
}) The following code snippet shows my current implementation of export function serverRoute<Load extends Kit.ServerLoad>(permission: Permission, handler: Load): Load {
return async (event) => {
checkAccess(event.locals, permission)
return handler(event)
}
} However, typescript complains with:
In theory, I understand the error message. Unfortunately, I fail to understand why it happens in my concrete case. The code only asks for an "original" handler, performs some actions beforehand, calls the handler and returns its result unchanged. Would anyone mind sharing some ideas on the mitigate this error? My only requirement would be that the type interference still works and the |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 7 replies
-
I've struggled with this too, though in my case I wrap action functions (for reasons that we need not go into.) I think the issue is that some of the generated types ( Whatever the case, it requires your wrapper function to be similarly typed. So, you can get around the typescript errors but at the expense of a bit of ugliness and verbosity. For your example above, here's what seems to work (i.e. typescript doesn't complain, and SvelteKit infers the correct shape of PageData back into export function serverRoute<
WhatYourFuncReturns extends Record<string, unknown>,
RouteParams extends Partial<Record<string, string>> = Partial<Record<string, string>>,
ParentData extends Record<string, unknown> = Record<string, unknown>,
RouteId extends string | null = string | null
>(
permission: any,
handler: (
event: ServerLoadEvent<RouteParams, ParentData, RouteId>
) => Promise<WhatYourFuncReturns>
): ServerLoad<RouteParams, ParentData, WhatYourFuncReturns, RouteId> {
const wrapper = async (
event: ServerLoadEvent<RouteParams, ParentData, RouteId>
) => {
checkAccess(event.locals, permission)
return await handler(event);
};
return wrapper;
} ...and be similarly verbose in import { serverRoute } from '$lib/utils/server-route.server.js';
import type {
RouteParams,
RouteId,
PageServerLoadEvent,
PageServerParentData
} from './$types.js';
export const load = serverRoute<
{ foo: number },
RouteParams,
PageServerParentData,
RouteId
>(
'fooPermission',
async (
event: PageServerLoadEvent
) => {
console.log(event.cookies.get('wow'))
return Promise.resolve({foo: 9});
}
); Let me know if that helps. |
Beta Was this translation helpful? Give feedback.
I've struggled with this too, though in my case I wrap action functions (for reasons that we need not go into.) I think the issue is that some of the generated types (
RequestEvent
,PageServerLoad
, etc.) are perhaps over-typed and/or include unhelpful default types. I've considered filing an issue, but I'm not really sure that there's a better solution.Whatever the case, it requires your wrapper function to be similarly typed. So, you can get around the typescript errors but at the expense of a bit of ugliness and verbosity. For your example above, here's what seems to work (i.e. typescript doesn't complain, and SvelteKit infers the correct shape of PageData back into
./$types
.) Do this f…