如何在 TypeScript 中扩展宿主对象(例如错误)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12915412/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I extend a host object (e.g. Error) in TypeScript
提问by Marijn Huizendveld
I would like to extend the host object Error
to a custom UploadError
class. The following example fails when I compile:
我想将宿主对象扩展Error
到自定义UploadError
类。以下示例在我编译时失败:
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:
当我运行 TypeScript 编译器时tsc
,出现以下错误:
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 :-)
它似乎Error
被定义为一个接口。如果有人知道实现的名称是什么,我会很高兴:-)
Update: I want to use Typescripts inheritance not prototypical inheritance like I currently employ to hack around this:
更新:我想使用 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;
}
采纳答案by Ron Buckton
I have found the following approach works:
我发现以下方法有效:
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);
}
}
The generated script looks like:
生成的脚本如下所示:
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);
回答by Aidiakapi
Update for TypeScript 1.6:
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
.
现在可以直接从Error
类中扩展,我原始答案中的代码仍然有效,但不再需要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).
这里的大多数答案都不符合我的要求。从 0.9.5 开始,最初接受的答案不再编译,但出现重复标识符异常。而且他们都没有真正的堆栈跟踪(JavaScript 问题,而不是 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); }
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.
您可以进行的一项改进是从堆栈跟踪中删除您的自定义代码,我个人认为堆栈跟踪仅适用于开发人员的眼睛,他们知道在哪里查看,所以对我来说没什么大不了的。
回答by Dmitry
pay attention on the new changes in Typescript 2.1 - link
注意 Typescript 2.1 的新变化 -链接
So you can extend the Error class but, as a recommendation, you need manually adjust the prototype immediately after any super(...) calls:
因此,您可以扩展 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;
}
}
回答by Fenton
Update
更新
TypeScript 1.6 is bringing the ability to extend native types, so when this lands you should be able to use
TypeScript 1.6 带来了扩展本机类型的能力,所以当它落地时你应该能够使用
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:
您可以在 TypeScript 中实现错误接口,但这不会让您访问,super
因为您没有使用继承:
class UploadError implements Error {
public name = "CustomError";
constructor (public message: string, private code: number){
}
}
throw new UploadError ("Something went wrong!", 123);
回答by tanguy_k
This is now possible to extend Error
class version 1.6. See pull request Allow expressions in class extends clauseshttps://github.com/Microsoft/TypeScript/pull/3516and issue Can not extend built in typeshttps://github.com/Microsoft/TypeScript/issues/1168
现在可以扩展Error
类版本 1.6。请参阅拉取请求允许类中的表达式扩展子句https://github.com/Microsoft/TypeScript/pull/3516和问题不能扩展内置类型https://github.com/Microsoft/TypeScript/issues/1168
Note that tsc
won't complain anymore but your editor/IDE will until it gets updated.
请注意,它tsc
不会再抱怨,但您的编辑器/IDE 会在更新之前一直抱怨。
回答by Miroslav Novak
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));
回答by Westy92
I'm using TypeScript 1.8 but this may work for earlier versions:
我正在使用 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;
}
};
Note that you must have the node
typings installed in order to use Error.captureStackTrace
.
请注意,您必须node
安装类型才能使用Error.captureStackTrace
.
回答by mindplay.dk
I know the answer has been accepted, and the solution is definitely impressive, but I really don't want that amount of code in my projects just for an exception.
我知道答案已被接受,解决方案绝对令人印象深刻,但我真的不希望我的项目中有那么多代码只是为了例外。
Until TypeScript gets proper exceptions at the language-level somehow, with Error being so cumbersome to extend, I'm now using the following very simple solution:
在 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!'));
Now, my error-types are really classes - you can extend them, and you will see the correct class-name on the console when an unhandled Error is thrown; but my Error objects are not instances of those classes: the constructor does notreturn an instance of MyError, it just applies it's own name to the Error instance you pass to it.
现在,我的错误类型实际上是类 - 您可以扩展它们,并且当抛出未处理的错误时,您将在控制台上看到正确的类名;但我的 Error 对象不是这些类的实例:构造函数不返回 MyError 的实例,它只是将它自己的名称应用于您传递给它的 Error 实例。
This also provides a simple work-around for the issue of Error producing it's stack-trace at the point where you construct it, rather than at the point where you throw it - since the constructor signature forces you to construct a "real" Error instance.
这也为错误问题提供了一个简单的解决方法,即在您构造它的时候产生堆栈跟踪,而不是在您抛出它的时候 - 因为构造函数签名迫使您构造一个“真实”的 Error 实例.
If you need to check the type of exception in your exception-handler, grab the ['type']
property and compare it using instanceof
:
如果您需要检查异常处理程序中的异常类型,请获取该['type']
属性并使用instanceof
以下命令进行比较:
try {
// something throws new MyError(new Error('aw snap!'))
} catch (error) {
console.log(error['type'] instanceof MyError); // => true
}
It's not ideal, but it's simple and it works.
这并不理想,但它很简单并且有效。
Be aware that, if you extend MyError, you will need to implement the constructor every time and add return super(...)
, since the default constructor generated by TypeScript does not expect constructors that use the return-statement. It does allow them though.
请注意,如果扩展 MyError,则每次都需要实现构造函数并添加return super(...)
,因为 TypeScript 生成的默认构造函数不期望使用 return 语句的构造函数。但它确实允许他们。
回答by engineforce
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:
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);
}
}
回答by Michael Zabka
I found solution. Is not nice, but working as well... using eval() JS function to ignore TypeScript check.
我找到了解决方案。不是很好,但也能正常工作……使用 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 { ... }