繁体   English   中英

打字稿 - 扩展错误类

[英]Typescript - Extending Error class

我试图抛出一个自定义错误,在控制台中打印我的“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 原型)?

您是否使用 typescript 2.1 版并转译为 ES5? 检查中断更改页面的这一部分可能的问题和解决方法: https : //github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-并且地图可能不再起作用

相关位:

作为建议,您可以在任何 super(...) 调用后立即手动调整原型。

 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.prototype 到此),但原型链本身无法修复。

问题在于,当您调用super并且新对象没有预期的原型链时,Javascript 的内置类Error通过将要构造的对象(即this )切换到一个新的不同对象来破坏原型链,即它是Error而不是CustomError的一个实例。

这个问题可以使用从 Typescript 2.2 开始支持的“new.target”优雅地解决,请参见此处: 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

它在 ES2015 ( https://jsfiddle.net/x40n2gyr/ ) 中正常工作。 最有可能的问题是 TypeScript 编译器正在转换为 ES5,并且仅使用 ES5 功能无法正确地对Error进行子类化; 它只能使用 ES2015 及更高版本的特性( class或更模糊地, Reflect.construct )正确地进行子类化。 这是因为当您将Error作为函数调用时(而不是通过new或者,在 ES2015 中, superReflect.construct ),它会忽略this并创建一个新的Error

在您可以针对 ES2015 或更高版本之前,您可能不得不忍受不完美的输出......

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

几天前,我在打字稿项目中遇到了同样的问题。 为了使它工作,我使用MDN的实现,只使用 vanilla js。 因此,您的错误将类似于以下内容:

 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 控制台和我的打字稿项目中起作用:

在此处输入图片说明

我从来没有在 SO 上发过帖子,但我的团队正在开发一个 TypeScript 项目,我们需要创建许多自定义错误类,同时还针对 es5。 在每个错误类中都执行建议的修复会非常乏味。 但是我们发现通过创建一个主要的自定义错误类,我们能够对所有后续错误类产生下游影响,并让我们的其余错误extend该类。 在该主要错误类中,我们执行以下操作以具有更新原型的下游效果:

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

class SomeNewError extends MainErrorClass {} 

...

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

只是希望这可以在将来避免其他人头疼!

尝试这个...

class CustomError extends Error { 

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

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

}

throw new CustomError('foo')

我在 nodejs 服务器中遇到了这个问题。 对我有用的是转译到 es2017,其中这些问题似乎得到了解决。

将 tsconfig 编辑为


    "target": "es2017"

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM