Typescript - 扩展错误类

2022-08-30 05:10:04

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


答案 1

您是否正在使用typescript版本2.1,并转译为ES5?请查看重大更改页面的此部分,了解可能的问题和解决方法:https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work

相关位:

作为建议,您可以在任何 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到此),但原型链本身无法修复。


答案 2

问题在于,Javascript 的内置类通过在调用时将要构造的对象(即)切换到一个新的、不同的对象来破坏原型链,而该新对象没有预期的原型链,即它是 not of 的实例。ErrorthissuperErrorCustomError

这个问题可以使用'new.target'优雅地解决,自Typescript 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.targetCustomError

如果你要对原型进行硬编码(例如),它本身将有一个工作原型链,但是从中继承的任何类都会被破坏,例如,a的实例不会像预期的那样,而只是。Object.setPrototype(this, CustomError.prototype)CustomErrorCustomErrorclass VeryCustomError < CustomErrorinstanceof VeryCustomErrorinstanceof CustomError

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