抛出自定义错误类却识别为Error实例而非自定义错误实例
问题描述
我创建了NotFoundError、ConflictError和UnauthorizedError等特定错误类,它们均继承自BaseError,而BaseError又继承自Node.js的Error类。
当抛出这些自定义错误时,我期望错误实例属于对应的自定义错误类。比如执行throw new UnauthorizedError('Missing api-key')时,错误实例应该是UnauthorizedError,但在errorHandler中间件中接收到的错误却变成了Error实例,导致无法按自定义类型返回对应响应。
相关逻辑如下:
error-handler.middleware.ts
export const errorHandler = (error: unknown, req: Request, res: Response, next: NextFunction) => { console.log('Instance of', error?.constructor.name); if (error instanceof ValidationError) { return res.status(error.status).json({ errors: error.errors }); } if (error instanceof UnauthorizedError) { return res.status(error.status).send({ error: error.message }); } if (error instanceof BaseError) { return res.status(error.status).send({ error: error.message }); } if (error instanceof Error) { return res.status(HttpCode.INTERNAL_SERVER_ERROR).json({ message: 'Internal Server Error', }); } next(); };
以下是相关错误类和中间件代码:
base.error.ts
export class BaseError extends Error { status: number; message: string; constructor(status: number, message: string) { super(message); this.status = status; this.message = message; } }
unauthorized.error.ts
import { BaseError } from './base.error'; export class UnauthorizedError extends BaseError { message: string; constructor(message: string = 'Unauthorized to perform this action') { super(HttpCode.UNAUTHORIZED, message); this.message = message; } }
api-key-handler.middleware.ts
export const validateApiKey = async (req: Request, res: Response, next: NextFunction) => { const code = req.headers['x-api-key'] as string; if (!code) { throw new UnauthorizedError('Missing api-key'); } next(); };
问题原因与解决方案
问题出在自定义Error类没有正确设置原型链。在TypeScript/JavaScript中继承内置Error类时,默认的原型链会被破坏,导致instanceof判断失效,错误实例会被识别为原生Error而非自定义类。
解决方案:修正BaseError的原型链
修改base.error.ts,在构造函数中添加原型链修正代码:
export class BaseError extends Error { status: number; message: string; constructor(status: number, message: string) { super(message); // 修正原型链,确保instanceof判断正确 Object.setPrototypeOf(this, BaseError.prototype); this.status = status; this.message = message; // 可选:保留原生Error的栈追踪信息 Error.captureStackTrace(this, this.constructor); } }
关键说明
- 调用
super()时,JavaScript会默认将实例原型指向Error.prototype,而非自定义类的原型,这直接导致instanceof判断失败。 Object.setPrototypeOf(this, BaseError.prototype)手动将实例原型指向自定义类的原型,恢复正确的继承关系。Error.captureStackTrace是可选操作,用于保留错误栈信息,和原生Error的行为保持一致。
额外提示
只要BaseError正确设置了原型链,所有继承它的子类(如UnauthorizedError)都会自动继承正确的原型链,无需在子类中重复操作。
内容的提问来源于stack exchange,提问作者Thore
相关产品推荐
相关产品推荐

