45

我想将主机对象扩展Error到自定义UploadError类。以下示例在我编译时失败:

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

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

当我运行 TypeScript 编译器时tsc,出现以下错误:

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

它似乎Error被定义为一个接口。如果有人知道实现的名称是什么,那会让我非常高兴:-)

更新:我想使用 Typescripts 继承,而不是像我目前用来解决这个问题的原型继承:

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;
}
4

11 回答 11

34

TypeScript 1.6 更新:

现在可以直接从Error类扩展,我原始答案中的代码仍然有效,但不再需要export declare class Error.

原答案:

这里的大多数答案都不符合我的要求。自 0.9.5 以来,最初接受的答案不再编译,出现重复标识符异常。而且它们都没有真正的堆栈跟踪(JavaScript 问题,而不是 TypeScript)。

对我来说,更优雅的解决方案是:

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;
        }
    }
}

你可以用它做什么:

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

我发现的唯一限制是您必须在模块中声明它,并且不能将它们设为全局。对我来说这不是问题,因为我认为模块有助于结构化,并且它们存在于我制作的任何应用程序中。

您可以进行的一项改进是从堆栈跟踪中删除您的自定义代码,我个人认为堆栈跟踪仅适用于开发人员的眼睛,他们知道在哪里看,所以对我来说没什么大不了的。

于 2014-03-26T15:39:53.130 回答
25

注意 Typescript 2.1 的新变化 -链接

因此,您可以扩展 Error 类,但作为建议,您需要在任何 super(...) 调用后立即手动调整原型:

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

        // Set the prototype explicitly.
        Object.setPrototypeOf(this, FooError.prototype);
    }

    sayHello() {
        return "hello " + this.message;
    }
}
于 2016-12-14T14:08:12.923 回答
10

更新

TypeScript 1.6 带来了扩展原生类型的能力,所以当它落地时,你应该能够使用

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

原始答案

您可以在 TypeScript 中实现错误接口,但这不会让您访问,super因为您没有使用继承:

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

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

    }
}

throw new UploadError ("Something went wrong!", 123);
于 2012-10-16T22:49:23.433 回答
10

我发现以下方法有效:

declare class ErrorClass implements Error {
    public name: string;
    public message: string;
    constructor(message?: string);
}
var ErrorClass = Error;

class MyError extends ErrorClass {
    public name = "MyError";
    constructor (public message?: string) {
        super(message);
    }
}

生成的脚本如下所示:

var ErrorClass = Error;
var MyError = (function (_super) {
    __extends(MyError, _super);
    function MyError(message) {
        _super.call(this, message);
        this.message = message;
        this.name = "MyError";
    }
    return MyError;
})(ErrorClass);
于 2012-11-16T03:58:14.860 回答
5

现在可以扩展Error类版本 1.6。请参阅拉取请求允许类中的表达式扩展子句 https://github.com/Microsoft/TypeScript/pull/3516和问题不能扩展内置类型 https://github.com/Microsoft/TypeScript/issues/1168

请注意,它tsc不会再抱怨了,但您的编辑器/IDE 会一直抱怨到它更新为止。

于 2015-06-24T22:50:20.703 回答
2

扩展接口是此处记录的一项重大更改。

解决方案:在构造函数中手动更改原型。

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));
于 2017-05-23T09:44:17.823 回答
1

我知道答案已被接受,并且解决方案绝对令人印象深刻,但我真的不希望我的项目中出现这么多代码只是为了例外。

直到 TypeScript 以某种方式在语言级别获得适当的异常,并且 Error 扩展起来非常麻烦,我现在使用以下非常简单的解决方案:

class MyError {
    constructor(error: Error) {
        error.name = this['constructor'].name;
        error['type'] = this; // for type-checking in exception-handlers

        return error;
    }
}

throw new MyError(new Error('aw snap!'));

现在,我的错误类型是真正的类——你可以扩展它们,当抛出未处理的错误时,你会在控制台上看到正确的类名;但我的 Error 对象不是这些类的实例:构造函数返回 MyError 的实例,它只是将它自己的名称应用于您传递给它的 Error 实例。

这也为 Error 在您构造它的点而不是在您抛出它的点产生堆栈跟踪的问题提供了一个简单的解决方法 - 因为构造函数签名会强制您构造一个“真实的”错误实例.

如果您需要检查异常处理程序中的异常类型,请获取该['type']属性并使用以下方法进行比较instanceof

try {
    // something throws new MyError(new Error('aw snap!'))
} catch (error) {
    console.log(error['type'] instanceof MyError); // => true
}

这并不理想,但它很简单并且有效。

请注意,如果您扩展 MyError,则每次都需要实现构造函数并添加return super(...),因为 TypeScript 生成的默认构造函数不期望使用返回语句的构造函数。它确实允许他们。

于 2013-11-06T15:28:53.083 回答
1

Ron Buckton 的解决方案在使用 TypeScript 0.8.3 时对我有用,但它不能在 TypeScript 0.9.5 中编译。TypeScript 生成编译错误:重复标识符“ErrorClass”。我已更改代码以使其再次工作:

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);
    }
}
于 2014-02-18T14:33:36.247 回答
1

我找到了解决方案。不好,但工作得很好......使用 eval() JS 函数来忽略 TypeScript 检查。

declare class ErrorClass implements Error {
    public name: string;
    public message: string;
    constructor(message?: string);
}
eval('ErrorClass = Error');

export = Exception;
class Exception extends ErrorClass implements Error { ... }
于 2015-02-26T09:11:47.700 回答
1

我使用的是 TypeScript 1.8,但这可能适用于早期版本:

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;
  }

};

请注意,您必须node安装类型才能使用Error.captureStackTrace.

于 2016-07-30T05:04:18.223 回答
0

您可以使用原型添加功能和属性:

interface Error {
   code: number;
   getCode(): number;
}   

Error.prototype.code = 1;

Error.prototype.getCode = function () {
    return this.code;
}  
var myError = new Error();
console.log("Code: " + myError.getCode());

运行时node.js,会产生以下输出:

Code: 1

错误定义lib.d.ts如下:

interface Error {
    name: string;
    message: string;
}

declare var Error: {
    new (message?: string): Error;
    (message?: string): Error;
    prototype: Error;
}

除此之外,我只看到定义您自己的扩展接口的明显解决方案Error

interface MyErrorInterface extends Error {       
    code: number;       
    getCode(): number;    
}       
class MyError implements MyErrorInterface {      
    code : number;      
    name : string;      
    message : string;
    constructor(code: number, name? : string, message? : string) {
        this.code = code;
        this.name = name;
        this.message = message;
    }   
    getCode(): number {
        return this.code;
    }   
}   

var myError = new MyError(1);
console.log("Code: " + myError.getCode());
于 2012-10-16T13:13:50.797 回答