如何在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被定义为一个接口。 如果有人知道这个实现的名字是什么,它会让我非常高兴:-)

更新:我想使用Typescriptsinheritance不是原型inheritance,就像我目前用来破解这个:

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

我发现以下方法的作品:

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

TypeScript 1.6更新:

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

原始答案:

这里的大部分答案都不符合我的要求。 原来接受的答案自0.9.5以来不再编译,具有重复的标识符exception。 而非他们真的有一个堆栈跟踪(JavaScript问题,而不是TypeScript)。

对我来说一个更优雅的解决scheme是:

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

我发现的唯一限制是你必须在一个模块中声明它,并且不能使它们成为全局的。 对我来说,这不是一个问题,因为我认为一个模块有助于构build,而且在我所做的任何应用程序中都有。

你可以做的一个改进就是从堆栈跟踪中去除你自定义的代码,我个人认为堆栈跟踪只针对开发者的眼睛,而且他们知道在哪里看,所以对我来说没什么大不了的。

关注Typescript 2.1 – 链接中的新变化

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

 class FooError extends Error { constructor(m: string) { super(m); // Set the prototype explicitly. Object.setPrototypeOf(this, FooError.prototype); } sayHello() { return "hello " + this.message; } } 

更新

TypeScript 1.6带来了扩展本地types的能力,所以当这种情况下你应该可以使用

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

原始答复

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

 class UploadError implements Error { public name = "CustomError"; constructor (public message: string, private code: number){ } } throw new UploadError ("Something went wrong!", 123); 

现在可以扩展Error class版本1.6。 请参阅拉请求允许类中的expression式扩展子句 https://github.com/Microsoft/TypeScript/pull/3516和问题;无法扩展内置types https://github.com/Microsoft/TypeScript/issues/1168

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

我find解决scheme。 不好,但工作以及…使用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 { ... } 

我知道答案已被接受,解决scheme是绝对令人印象深刻的,但我真的不希望我的项目中的代码量只是一个例外。

在TypeScript以某种方式在语言级别获得适当的exception之前,错误是非常繁琐的扩展,现在我使用以下非常简单的解决scheme:

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

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

这也提供了一个简单的解决方法,在产生它的堆栈跟踪的地方,而不是在你抛出它的地方,因为构造函数签名迫使你构造一个“真正的”错误实例。

如果您需要检查exception处理程序中的exceptiontypes,请抓住['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语句的构造函数。 它确实允许他们。

在使用TypeScript 0.8.3的时候,Ron Buckton的解决scheme为我工作,但是它不能在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); } } 

我正在使用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

扩展接口是一个突破性的变化logging在这里 。

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

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

您可以使用原型来添加function和属性:

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

除此之外,我只看到明显的解决scheme来定义自己的扩展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());