I'm in the process of creating a custom controller function to streamline my application. The repetitive task of wrapping try-catch, parsing a zod schema, and merging the request zod schema into a single object is present in all handler functions. Therefore, I am looking to create a wrapper to handle these tasks for each request. My main goal is to maintain type safety throughout the process. Below is the current function I have implemented:
function controller<
T extends B & Q & P,
B extends Record<string, any>,
Q extends Record<string, any>,
P extends Record<string, any>
>(handlerFn: (args: T) => Promise<any>, zodSchema: { parse: (data: unknown) => { body: B; query: Q; params: P } }) {
return async (req: express.Request, res: express.Response, next: express.NextFunction) => {
try {
const r = zodSchema.parse(req);
const args = { ...r.body, ...r.params, ...r.query };
await handlerFn(args);
} catch (e) {
next(e);
}
};
}
This function takes a handlerFn
, which is the core function requiring a parameter T. It also accepts a zodSchema
as its second parameter, responsible for validating and returning the body, query, and params fields after parsing to validate the Request object. The input of the handlerFn
should be a merge of body, query, and params.
The error message I encounter is:
Argument of type 'B & P & Q' is not assignable to parameter of type 'T'.
'B & P & Q' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Record<string, any>'.
If anyone has insights or solutions, I would greatly appreciate your help.