2016-12-12 10 views
17

ノー成功を収めて、私のコンソールに印刷された「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プロトタイプを乱さずに)?

+1

'ParameterUndefinedError'何ですか? –

+0

@NitzanTomerそれはタイプミスです。私はそれを修正した、ありがとう。 – darksoulsong

答えて

16

あなたはtypescriptですバージョン2.1を使用して、ES5にtranspilingている...あなたはES2015以上を標的にすることができるまで、不完全な出力と一緒に暮らす必要がありますか?可能性の問題と回避策のための破壊の変更ページのこのセクションを確認してください: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

はい、私はES5に移っています。提案したプロトタイプを設定しようとしましたが、残念ながら動作しませんでした。 – darksoulsong

+1

残念ながら、 'Object.setPrototypeOf(this、this.constructor.prototype)'はここでは動作しませんが、クラスは明示的に参照されなければなりません。 –

+1

@ JohnWeiszここで 'this.constructor'からプロトタイプを読むことができれば、あなたが言及している修正がうまくいけば、最初は何も修正されません。プロトタイプチェーンはすでに元の状態になります。 – thetrompf

5

ES2015(https://jsfiddle.net/x40n2gyr/)では正しく動作します。おそらく、問題はTypeScriptコンパイラがES5に移行しており、ErrorはES5機能のみを使用して正しくサブクラス化できないことです。それはES2015以上の機能(classか、より曖昧にはReflect.construct)を使って正しくサブクラス化することができます。あなたが(ES2015、superまたはReflect.constructではなく、newを介して、または)関数としてErrorを呼び出すとき、それはthisを無視し、新しいErrorを作成するためです。

おそらく

6

数日前に私のタイスクリプトプロジェクトで同じ問題が発生しました。それを動作させるために、私はMDNから実装を使用し、バニラ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コードスニペットで動作するようには思えないが、それはクロームコンソールで、私のtypescriptですプロジェクトで行います。

enter image description here

+0

アイデアが好きで、タイプスクリプトで実装できません –

+0

本当ですか?私のタイスクリプトはネイティブプロジェクトに反応しました。 –

+0

さて、私はまた、定型部分を抽象化したいと思っていましたが、おそらく失敗しました。他のshinanigensなしでもう一度試してみます。 –

0

問題ではJavaScriptの組み込みクラスErrorブレイクように構成するオブジェクトを切り替えることにより、プロトタイプチェーン(つまり、です新しいオブジェクトが予想されるプロトタイプチェーンを持たない、すなわち、新しいオブジェクトが新しいオブジェクトに変換されます。つまり、superを呼び出すと、CustomerErrorではないErrorのインスタンスです。

この問題は、エレガントな活字体2.2からサポートされた「new.target」を使用して解決することができ、ここを参照してください: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__ = new.target.prototype; } 
    } 
} 

あなたはプロトタイプをハードコーディングする必要がないという利点を持っていますここに提案されているいくつかの他の回答と同様です。これには、CustomErrorから継承するクラスも自動的に正しいプロトタイプチェーンを取得するという利点があります。

あなたはプロトタイプ(例えばObject.setPrototype(this, CustomError.prototype))をハードコーディングした場合、例えば、CustomError自体が動作するプロトタイプチェーンを持っているだろうが、CustomErrorから継承されたクラスが壊れてしまうがclass VeryCustomError < CustomErrorのインスタンスは、期待通りにinstanceof VeryCustomErrorではなく、instanceof CustomErrorのみです。

も参照してください:https://github.com/Microsoft/TypeScript/issues/13965#issuecomment-278570200