Typescript - 扩展错误类

时间:2016-12-12 13:32:29

标签: javascript typescript

我试图用我的" CustomError"类名称在控制台中打印而不是"错误",但没有成功:

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原型)?

7 个答案:

答案 0 :(得分:49)

您使用的是打字稿版本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

相关位:

  

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

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

答案 1 :(得分:36)

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

使用'new.target'可以很好地解决这个问题,自从Typescript 2.2以来一直支持,请看这里:https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html

CustomError

使用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

另请参阅:https://github.com/Microsoft/TypeScript/issues/13965#issuecomment-278570200

答案 2 :(得分:9)

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

你可能不得不忍受不完美的输出,直到你可以瞄准ES2015或更高......

答案 3 :(得分:5)

我几天前在我的打字稿项目中遇到了同样的问题。为了使它工作,我使用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控制台和我的打字稿项目中有效:

enter image description here

答案 4 :(得分:3)

从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
        Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain
    }
}

答案 5 :(得分:2)

我实际上从不发布SO,但是我的团队正在研究TypeScript项目,我们需要创建许多自定义错误类,同时还要针对es5。在每个错误类中执行建议的修复工作将非常繁琐。但是我们发现,通过创建一个主要的自定义错误类并让其余错误extend对该类产生影响,便能够对所有后续错误类产生下游影响。在该主要错误类内部,我们进行了以下操作,以产生更新原型的下游影响:

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

class SomeNewError extends MainErrorClass {} 

...

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

只是希望这可以节省其他人将来的头痛!

答案 6 :(得分:1)

尝试一下...

class CustomError extends Error { 

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

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

}

throw new CustomError('foo')