如何在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());