diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 0000000..3720cf0 --- /dev/null +++ b/index.d.ts @@ -0,0 +1,22 @@ +// TypeScript definitions for http-errors + +export interface HttpError extends Error { + status: number; + statusCode: number; + expose: boolean; +} + +interface CreateHttpError { + (status: number, message?: string): HttpError; + (status: number, err: Error, props?: object): HttpError; + (status: number, props: object): HttpError; + (message: string, status?: number): HttpError; + (err: Error, props?: object): HttpError; + HttpError: { + new(status: number, message?: string): HttpError; + }; + isHttpError(val: any): boolean; +} + +declare const createError: CreateHttpError; +export = createError; diff --git a/index.js b/index.js index 82271f6..5c1a143 100644 --- a/index.js +++ b/index.js @@ -110,12 +110,16 @@ function createError () { */ function createHttpErrorConstructor () { - function HttpError () { - throw new TypeError('cannot construct abstract class') + class HttpError extends Error { + constructor (status, message) { + super(message != null ? message : statuses.message[status] || 'Error') + this.status = status != null ? status : 500 + this.statusCode = this.status + this.expose = this.status < 500 + // Set the name for consistency + this.name = 'HttpError' + } } - - inherits(HttpError, Error) - return HttpError } diff --git a/test/test.js b/test/test.js index 7db9f16..d9e7d6f 100644 --- a/test/test.js +++ b/test/test.js @@ -31,6 +31,23 @@ describe('createError(status)', function () { assert.ok(isError(createError(500))) }) + describe('ES6 class extension (issue #98)', function () { + it('should allow extending HttpError with ES6 class', function () { + class MyHttpError extends createError.HttpError { + constructor (message) { + super(418, message) + this.custom = true + } + } + const err = new MyHttpError('I am a teapot') + assert.strictEqual(err.status, 418) + assert.strictEqual(err.message, 'I am a teapot') + assert.strictEqual(err.custom, true) + assert.ok(err instanceof createError.HttpError) + assert.ok(err instanceof Error) + }) + }) + describe('Extending Existing Errors with HTTP Properties', function () { it('should extend existing error without altering its prototype or replacing the object', function () { var nativeError = new Error('This is a test error') @@ -377,9 +394,13 @@ describe('HTTP Errors', function () { }) it('new createError.HttpError()', function () { - assert.throws(function () { - new createError.HttpError() // eslint-disable-line no-new - }, /cannot construct abstract class/) + var err = new createError.HttpError(404, 'Not Found') + assert.strictEqual(err.name, 'HttpError') + assert.strictEqual(err.message, 'Not Found') + assert.strictEqual(err.status, 404) + assert.strictEqual(err.statusCode, 404) + assert.strictEqual(err.expose, true) + assert(err.stack) }) it('new createError.NotFound()', function () { diff --git a/test/typings.test.ts b/test/typings.test.ts new file mode 100644 index 0000000..b38702d --- /dev/null +++ b/test/typings.test.ts @@ -0,0 +1,20 @@ +// TypeScript compilation test for http-errors +import { HttpError } from '../index'; +import * as createError from '../index'; + +// Test that HttpError can be used as a type +let err: HttpError = createError(404, 'not found'); +err.status; +err.expose; + +// Test that HttpError can be extended (workaround for abstract class) +class MyHttpError extends (createError.HttpError as { new(status: number, message: string): HttpError }) { + custom: boolean; + constructor(message: string) { + super(418, message); + this.custom = true; + } +} +const myErr = new MyHttpError('I am a teapot'); +myErr.status; +myErr.custom;