类型-扩展错误类

我试图抛出一个自定义错误,我的“ CustomError”类名打印在控制台中,而不是“ Error”,没有成功:

class CustomError extends Error {
constructor(message: string) {
super(`Lorem "${message}" ipsum dolor.`);
this.name = 'CustomError';
}
}
throw new CustomError('foo');

输出是 Uncaught Error: Lorem "foo" ipsum dolor

我的期望值: Uncaught CustomError: Lorem "foo" ipsum dolor

我想知道是否可以做到这一点,只使用 TS (而不与 JS 原型) ?

103147 次浏览

它在 ES2015(https://jsfiddle.net/x40n2gyr/)中正确工作。最有可能的问题是 TypeScript 编译器正在转移到 ES5,并且仅使用 ES5特性无法正确地子类化 Error; 它只能使用 ES2015及以上特性(class或者更不明显的 Reflect.construct)才能正确地子类化。这是因为当您将 Error作为函数调用时(而不是通过 new或 ES2015中的 superReflect.construct) ,它将忽略 this并创建一个 class0 Error

您可能不得不忍受不完美的输出,直到您可以针对 ES2015或更高..。

Are you using typescript version 2.1, and transpiling to ES5? Check this section of the breaking changes page for possible issues and workaround: https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work

相关部分:

As a recommendation, you can manually adjust the prototype immediately after any super(...) calls.

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


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


sayHello() {
return "hello " + this.message;
}
}

但是,FooError 的任何子类也必须手动设置原型。对于不支持 Object.setPrototypeOf 的运行时,您可以使用 __proto__

不幸的是,这些变通方法对 Internet Explorer 10和优先级不起作用。我们可以手动地将方法从原型复制到实例本身(例如,FooError.model 复制到这个实例) ,但是原型链本身无法修复。

I ran into the same problem in my typescript project a few days ago. To make it work, I use the implementation from MDN using only vanilla js. So your error would look something like the following:

function CustomError(message) {
this.name = 'CustomError';
this.message = message || 'Default Message';
this.stack = (new Error()).stack;
}
CustomError.prototype = Object.create(Error.prototype);
CustomError.prototype.constructor = CustomError;


throw new CustomError('foo');

它似乎不能在 SO 代码片段中工作,但是在 chrome 控制台和我的打字机项目中可以:

enter image description here

The problem is that Javascript's built-in class Error breaks the prototype chain by switching the object to be constructed (i.e. this) to a new, different object, when you call super and that new object doesn't have the expected prototype chain, i.e. it's an instance of Error not of CustomError.

这个问题可以通过使用‘ new.target’来优雅地解决,这个问题从 Typecript 2.2开始就得到了支持,参见: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html

class CustomError extends Error {
constructor(message?: string) {
// 'Error' breaks prototype chain here
super(message);


// restore prototype chain
const actualProto = new.target.prototype;


if (Object.setPrototypeOf) { Object.setPrototypeOf(this, actualProto); }
else { this.__proto__ = actualProto; }
}
}

使用 new.target的优点是您不必像这里提出的其他解决方案一样对原型进行硬编码。这样做的好处是,从 CustomError继承的类也将自动获得正确的原型链。

如果你硬编码原型(例如 Object.setPrototype(this, CustomError.prototype)) ,CustomError本身会有一个工作的原型链,但是从 CustomError继承的任何类都会被破坏,例如 class VeryCustomError < CustomError的实例不会像预期的那样是 instanceof VeryCustomError,而只是 instanceof CustomError

参见: https://github.com/Microsoft/TypeScript/issues/13965#issuecomment-278570200

在 TypeScript 2.2中,它可以通过 new.target.prototype完成。 Https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#example

class CustomError extends Error {
constructor(message?: string) {
super(message); // 'Error' breaks prototype chain here
this.name = 'CustomError';
Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain
}
}

试试这个..。

class CustomError extends Error {


constructor(message: string) {
super(`Lorem "${message}" ipsum dolor.`)
}


get name() { return this.constructor.name }


}


throw new CustomError('foo')

我从来没有在 SO 上发表过文章,但是我的团队正在进行一个 TypeScript 项目,我们需要创建许多自定义错误类,同时也针对 es5。在每个单独的错误类中执行建议的修复是非常乏味的。但是我们发现,通过创建一个主要的自定义错误类,并让其余的错误 extend成为该类,我们能够对所有后续的错误类产生下游影响。在这个主要错误类中,我们做了以下工作来产生更新原型的下游效果:

class MainErrorClass extends Error {
constructor() {
super()
Object.setPrototypeOf(this, new.target.prototype)
}
}


class SomeNewError extends MainErrorClass {}


...

使用 new.target.prototype是使所有继承错误类得到更新而不需要更新每个类的构造函数的关键。

Just hoping this saves someone else a headache in the future!

我在 nodejs 服务器上遇到了这个问题。对我有效的方法是把这些问题延伸到2017年的 es2017年,这些问题似乎已经得到解决。

编辑 tsconfig 到


"target": "es2017"