如何在TypeScript中扩展宿主对象(例如,错误)

时间:2012-10-16 13:07:33

标签: inheritance typescript

我想将主机对象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;
}

11 个答案:

答案 0 :(得分:33)

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

我发现的唯一限制是你必须在一个模块中声明它,并且不能使它们全局化。对我来说这不是问题,因为我认为一个模块有助于结构化,他们在我的任何申请中都有。

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

答案 1 :(得分:21)

关注Typescript 2.1中的新变化 - link

所以你可以扩展Error类,但作为建议,你需要在任何超级(...)调用后立即手动调整原型:

  private DataTable CreateResultDataTable()
    {
        DataTable Result = new DataTable();
        foreach (DataGridViewRow row in dataGridView1.Rows)
        {
            var cell = row.Cells[1].Value;
            if(cell!=null){
            Result.Columns.Add(cell.ToString()); // why is Value null here ??
           }
        }
        return Result;
    }

答案 2 :(得分: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);

答案 3 :(得分: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);

答案 4 :(得分:6)

现在可以扩展Error类版本1.6。请参阅拉取请求允许在类扩展子句中使用表达式 https://github.com/Microsoft/TypeScript/pull/3516并发出无法扩展内置类型 https://github.com/Microsoft/TypeScript/issues/1168

请注意,tsc不会再抱怨,但您的编辑器/ IDE将会更新。

答案 5 :(得分: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!'));

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

这也提供了一个简单的解决方法,用于在构造它时产生它的堆栈跟踪错误,而不是在你抛出它的位置 - 因为构造函数签名强迫你建立一个真正的&#34;错误实例。

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

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

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

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

答案 6 :(得分:1)

使用TypeScript 0.8.3时,Ron Buckton的解决方案对我有用,但它不能在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);
    }
}

答案 7 :(得分: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 { ... }

答案 8 :(得分: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

答案 9 :(得分:1)

扩展接口是记录here的重大变化。

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

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

答案 10 :(得分: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());