Reputation: 23140
I'm trying to convert an existing node.js project from javascript to typescript. I've been using the default 404 error catcher from the Visual Studio Express 4 template:
// catch 404 and forward to error handler
app.use(function (req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
However, I'm getting the following error message: Property 'status' does not exist on type 'Error'.
I get a similar message if I try and invoke the Error's .stack property: Property 'stack' does not exist on type 'Error'.
Does anyone know what's going on here?
Edit: Steve Fenton points out that I could just put the error status on the response object. However, my error handling mechanism uses a two-step process:
Hand it on to the following generic handler:
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
So the error status is first set on the Error object, then read back by the error handler to decide how to handle the error.
Upvotes: 41
Views: 51246
Reputation: 276085
Error
You can tell TypeScript that for your use case Error
might have a status
on it:
interface Error {
status?: number;
}
So you get:
interface Error {
status?: number;
}
var err = new Error('Not Found');
err.status = 404;
Put the status on the res
and send the err
. For Example:
// catch 404 and forward to error handler
app.use(function (req, res, next) {
var err = new Error('Not Found');
res.status(404); // using response here
next(err);
});
Upvotes: 32
Reputation: 171
If I am not mistaken it is always best to get the type that is actually expected. I couldn't find any hard support that I am right, but I use:
import createError, { HttpError } from 'http-errors';
and to be complete for all types I also import the parameter types of use:
import express, { Request, Response, NextFunction } from 'express';
The actual function I use then looks like this:
app.use((err: HttpError, req: Request, res: Response, next: NextFunction) => { ... }
In your case if you want to create your own error:
app.use((req: Request, res: Response, next: NextFunction) => {
next(createError(404));
});
or closer to your code:
app.use((req: Request, res: Response, next: NextFunction) => {
let err = new HttpError('Not found');
err.status = 404;
next(err);
});
Upvotes: 8
Reputation: 3605
This is generally a question of how to lazily initialize objects in Typescript.
The ideal way to do this is:
interface ErrorWithStatus extends Error {
status: string
}
let foo = new Error() as ErrorWithStatus;
foo.status = '404';
Using any
, or interfaces with nullable fields, leave you with subpar and weak contracts.
Upvotes: 8
Reputation: 311
import * as express from 'express';
interface Error {
status?: number;
message?: string;
}
app.use((err: Error, req: express.Request, res: express.Response, next: express.NextFunction) => {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
Upvotes: 12
Reputation: 251022
You put the error code on the response...
app.use(function (req, res, next) {
var err = new Error('Not Found');
res.status(404)
next(err);
});
Upvotes: 8
Reputation: 3531
The best way in my opinion, is not to disable type checks by setting the error to any
, or creating a new Error
type, since one already exists in @types/node
.
Instead, you should extend that error type:
interface ResponseError extends Error {
status?: number;
}
Upvotes: 30
Reputation: 10263
Another option in TypeScript:
let err: any;
err = new Error();
err.status = 404;
Upvotes: 3
Reputation: 944
I just went for
var err = new Error('Not Found');
err['status'] = 404;
Upvotes: 0