How do I extend a host object (e.g. Error) in Type

2020-01-31 02:30发布

I would like to extend the host object Error to a custom UploadError class. The following example fails when I compile:

class UploadError extends Error {
    constructor(message: string, private code: number) {
        super(message);
    }

    getCode(): number {
        return this.code;
    }
}

When I run the TypeScript compiler tsc I get the following error:

UploadError.ts(1,0): A export class may only extend other classes, Error is an interface.

It seems Error is defined as an interface. If anyone knows what the name of the implementation is it would make me very happy :-)

Update: I want to use Typescripts inheritance not prototypical inheritance like I currently employ to hack around this:

function UploadError (message: string, code: number) {
    this.message = message;
    this.code = code;
}

UploadError.prototype = new Error();

UploadError.prototype.constructor = UploadError;

UploadError.prototype.getCode = (): number => {
    return this.code;
}

11条回答
你好瞎i
2楼-- · 2020-01-31 03:14

Update

TypeScript 1.6 is bringing the ability to extend native types, so when this lands you should be able to use

class UploadError extends Error {
    //... calls to super and all that jazz
}

Original Answer

You can implement the error interface in TypeScript, but this won't give you access to super as you aren't using inheritance:

class UploadError implements Error {
    public name = "CustomError";

    constructor (public message: string, private code: number){

    }
}

throw new UploadError ("Something went wrong!", 123);
查看更多
手持菜刀,她持情操
3楼-- · 2020-01-31 03:16

Update for TypeScript 1.6:

It's now possible to directly extend from the Error class, the code in my original answer still works, but there's no longer a need for the export declare class Error.

Original answer:

Most of the answers here don't meet my requirements. The originally accepted answer doesn't compile anymore since 0.9.5 with a duplicate identifier exception. And non of them really have a stack trace (a JavaScript issue, not TypeScript).

For me a more elegant solution is:

module YourModule {
    export declare class Error {
        public name: string;
        public message: string;
        public stack: string;
        constructor(message?: string);
    }

    export class Exception extends Error {

        constructor(public message: string) {
            super(message);
            this.name = 'Exception';
            this.message = message;
            this.stack = (<any>new Error()).stack;
        }
        toString() {
            return this.name + ': ' + this.message;
        }
    }
}

What you can do with it:

  • new Exception("msg") instanceof Error == true
  • class SpecificException extends Exception
  • catch (e) { console.log(e.stack); }

The only limitation I found was that you have to declare it in a module, and cannot make them global. For me this isn't an issue since I think a module helps in structuring, and they are there in any application I make.

One improvement you could make is strip your custom code from the stack trace, personally I think stacktraces are only for the eyes of developers, and they know where to look, so it's no big deal for me.

查看更多
Rolldiameter
4楼-- · 2020-01-31 03:22

I'm using TypeScript 1.8 but this may work for earlier versions:

class MyError extends Error {

  static name: string;

  constructor(public message?: string, public extra?: number) {
    super(message);
    Error.captureStackTrace(this, MyError);
    this.name = (this as any).constructor.name; // OR (<any>this).constructor.name;
  }

};

Note that you must have the node typings installed in order to use Error.captureStackTrace.

查看更多
淡お忘
5楼-- · 2020-01-31 03:24

Ron Buckton's solution worked for me when using TypeScript 0.8.3, but it does not compile in TypeScript 0.9.5. TypeScript generate compilation error: Duplicate identifier 'ErrorClass'. I have changed the code to make it work again:

declare class ErrorClass {
    public name: string;
    public message: string;
    constructor(message?: string);
}

// Move following line to a JavaScript
// (not TypeScript) file. 
// var ErrorClass = Error;

class MyError extends ErrorClass {
    public name = "MyError";
    constructor (public message?: string) {
        super(message);
    }
}
查看更多
Juvenile、少年°
6楼-- · 2020-01-31 03:25

Extending interfaces is a breaking change documented here.

Solution: change manually prototype in your constructor.

class MyError extends Error {
    constructor(m: string) {
        super(m);

        // Set the prototype explicitly. If you skip this, iinstanceof will not work :-(
        (<any>this).__proto__ = MyError.prototype;
    }
}

console.log("Instance of works now: "+(new MyError("my error") instanceof MyError));
查看更多
登录 后发表回答