With some familiarity with TypeScript but a newcomer to Express.js, I aim to develop a generic error handler for my Express.js app built in TypeScript. The code snippet below is functional in JavaScript:
// catch 404 and forward to error handler
app.use((req, res, next) => {
next(new createError[404]());
});
// error handler
app.use((err, req, res, next) => {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
However, when attempting to compile this using TypeScript, an issue arises with the anonymous function in the second app.use
call:
error TS7006: Parameter 'err' implicitly has an 'any' type.
app.use((err, req, res, next) => {
~~~
error TS7006: Parameter 'req' implicitly has an 'any' type.
app.use((err, req, res, next) => {
~~~
error TS7006: Parameter 'res' implicitly has an 'any' type.
app.use((err, req, res, next) => {
~~~
error TS7006: Parameter 'next' implicitly has an 'any' type.
app.use((err, req, res, next) => {
~~~~
Evidently, TypeScript managed to infer the parameter types for the first anonymous function in the first app.use
call, but not for the second one.
By modifying the line as follows, TypeScript no longer throws any errors... although now eslint
flags it for utilizing implicit any
s:
app.use((err: any, req: any, res: any, next: any) => {
In another approach, Visual Studio Code offers a quick fix option "Infer parameter types from usage" for the second anonymous function. This results in the following format for the second app.use
line (with added line breaks for clarity):
app.use((err: { message: any; status: any; },
req: { app: { get: (arg0: string) => string; }; },
res: { locals: { message: any; error: any; };
status: (arg0: any) => void;
render: (arg0: string) => void; },
next: any) => {
While this may function appropriately, I find it rather unwieldy and difficult to comprehend.
Hence, the question arises: How can a similar implementation be achieved without sacrificing maintainability and comprehensibility?