ES6とBabelでエラーを拡張しようとしています。うまくいきません。
class MyError extends Error {
constructor(m) {
super(m);
}
}
var error = new Error("ll");
var myerror = new MyError("ll");
console.log(error.message) //shows up correctly
console.log(myerror.message) //shows empty string
Errorオブジェクトが正しいメッセージセットを取得することはありません。
今、私はSO( たとえばここ )でいくつかの解決策を見ましたが、それらはすべて非常に非ES6-yのようです。ニース、ES6の方法でそれを行う方法? (それはバベルで働いています)
KarelBílekの答えに基づいて、constructor
に小さな変更を加えます。
class ExtendableError extends Error {
constructor(message) {
super(message);
this.name = this.constructor.name;
if (typeof Error.captureStackTrace === 'function') {
Error.captureStackTrace(this, this.constructor);
} else {
this.stack = (new Error(message)).stack;
}
}
}
// now I can extend
class MyError extends ExtendableError {}
var myerror = new MyError("ll");
console.log(myerror.message);
console.log(myerror instanceof Error);
console.log(myerror.name);
console.log(myerror.stack);
これにより、スタック内のMyError
が出力され、汎用のError
は出力されません。
また、エラーメッセージをスタックトレースに追加します-Karelの例にはありませんでした。
また、使用可能な場合はcaptureStackTrace
も使用します。
Babel 6では、これが機能するために transform-builtin-extend ( npm )が必要です。
this answer 、 this answer 、および this code を組み合わせて、この小さな「ヘルパー」クラスを作成しました。
class ExtendableError extends Error {
constructor(message) {
super();
this.message = message;
this.stack = (new Error()).stack;
this.name = this.constructor.name;
}
}
// now I can extend
class MyError extends ExtendableError {
constructor(m) {
super(m);
}
}
var myerror = new MyError("ll");
console.log(myerror.message);
console.log(myerror instanceof Error);
console.log(myerror.name);
console.log(myerror.stack);
Edit: TypeScript 2.1 の変更を壊します
Error、Array、Mapなどの拡張ビルトインは機能しなくなる場合があります。
推奨事項として、super(...)呼び出しの直後にプロトタイプを手動で調整できます。
Lee Bensonのオリジナルの回答を少し編集すると、私にとってはうまくいきます。また、stack
クラスとExtendableError
クラスの追加メソッドがインスタンスに追加されます。
class ExtendableError extends Error {
constructor(message) {
super(message);
Object.setPrototypeOf(this, ExtendableError.prototype);
this.name = this.constructor.name;
}
dump() {
return { message: this.message, stack: this.stack }
}
}
class MyError extends ExtendableError {
constructor(message) {
super(message);
Object.setPrototypeOf(this, MyError.prototype);
}
}
var myerror = new MyError("ll");
console.log(myerror.message);
console.log(myerror.dump());
console.log(myerror instanceof Error);
console.log(myerror.name);
console.log(myerror.stack);
Babel 6の最新の変更により、 transform-builtin-extend が機能しなくなったことがわかりました。私はこの混合アプローチを使用することになりました:
export default class MyError {
constructor (message) {
this.name = this.constructor.name;
this.message = message;
this.stack = (new Error(message)).stack;
}
}
MyError.prototype = Object.create(Error.prototype);
MyError.prototype.constructor = MyError;
そして
import MyError from './MyError';
export default class MyChildError extends MyError {
constructor (message) {
super(message);
}
}
その結果、これらすべてのテストに合格します。
const sut = new MyError('error message');
expect(sut.message).toBe('error message');
expect(sut).toBeInstanceOf(Error);
expect(sut).toBeInstanceOf(MyError);
expect(sut.name).toBe('MyError');
expect(typeof sut.stack).toBe('string');
const sut = new MyChildError('error message');
expect(sut.message).toBe('error message');
expect(sut).toBeInstanceOf(Error);
expect(sut).toBeInstanceOf(MyError);
expect(sut).toBeInstanceOf(MyChildError);
expect(sut.name).toBe('MyChildError');
expect(typeof sut.stack).toBe('string');
class MyError extends Error {
constructor(message) {
super(message);
this.message = message;
this.name = 'MyError';
}
}
this.stack = (new Error()).stack;
呼び出しのおかげで、super()
トリックの必要はありません。
上記のコードは、this.stack = (new Error()).stack;
またはError.captureStackTrace(this, this.constructor.name);
が Babel で呼び出されない限り、スタックトレースを出力できません。 IMO、それはおそらくここの1つの問題です。
実際、スタックトレースは、このコードスニペットでChrome console
およびNode.js v4.2.1
の下に出力できます。
class MyError extends Error{
constructor(msg) {
super(msg);
this.message = msg;
this.name = 'MyError';
}
};
var myerr = new MyError("test");
console.log(myerr.stack);
console.log(myerr);
Chrome console
の出力。
MyError: test
at MyError (<anonymous>:3:28)
at <anonymous>:12:19
at Object.InjectedScript._evaluateOn (<anonymous>:875:140)
at Object.InjectedScript._evaluateAndWrap (<anonymous>:808:34)
at Object.InjectedScript.evaluate (<anonymous>:664:21)
Node.js
の出力
MyError: test
at MyError (/home/bsadmin/test/test.js:5:8)
at Object.<anonymous> (/home/bsadmin/test/test.js:11:13)
at Module._compile (module.js:435:26)
at Object.Module._extensions..js (module.js:442:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:311:12)
at Function.Module.runMain (module.js:467:10)
at startup (node.js:134:18)
at node.js:961:3
@zangwの答えに加えて、次のようにエラーを定義できます。
'use strict';
class UserError extends Error {
constructor(msg) {
super(msg);
this.name = this.constructor.name;
}
}
// define errors
class MyError extends UserError {}
class MyOtherError extends UserError {}
console.log(new MyError instanceof Error); // true
throw new MyError('My message');
正しい名前、メッセージ、スタックトレースがスローされます:
MyError: My message
at UserError (/Users/honzicek/Projects/api/temp.js:5:10)
at MyError (/Users/honzicek/Projects/api/temp.js:10:1)
at Object.<anonymous> (/Users/honzicek/Projects/api/temp.js:14:7)
at Module._compile (module.js:434:26)
at Object.Module._extensions..js (module.js:452:10)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Function.Module.runMain (module.js:475:10)
at startup (node.js:117:18)
at node.js:951:3
ES6でエラーを拡張しようとしています
そのclass MyError extends Error {…}
構文は正しいです。
トランスパイラーには、組み込みオブジェクトからの継承にまだ問題があることに注意してください。あなたの場合、
var err = super(m);
Object.assign(this, err);
問題を修正するようです。
これを考えると、受け入れられた答えはもはや機能しません。代わりに常にファクトリを使用できます( repl ):
function ErrorFactory(name) {
return class AppError extends Error {
constructor(message) {
super(message);
this.name = name;
this.message = message;
if (typeof Error.captureStackTrace === 'function') {
Error.captureStackTrace(this, this.constructor);
} else {
this.stack = (new Error(message)).stack;
}
}
}
}
// now I can extend
const MyError = ErrorFactory("MyError");
var myerror = new MyError("ll");
console.log(myerror.message);
console.log(myerror instanceof Error);
console.log(myerror.name);
console.log(myerror.stack);
これは私のために働く:
/**
* @class AuthorizationError
* @extends {Error}
*/
export class AuthorizationError extends Error {
message = 'UNAUTHORIZED';
name = 'AuthorizationError';
}
@sukimaが言及しているように、ネイティブJSを拡張することはできません。 OPの質問には答えられません。
Melbourne2991の回答 と同様に、私はむしろ工場を使用しましたが、 顧客エラータイプに関するMDNの推奨 に従いました。
function extendError(className){
function CustomError(message){
this.name = className;
this.message = message;
this.stack = new Error().stack; // Optional
}
CustomError.prototype = Object.create(Error.prototype);
CustomError.prototype.constructor = CustomError;
return CustomError;
}
上記よりも強力な構文を好みます。エラータイプの追加メソッドは、かなりconsole.log
または何か他のものを作成するのに役立ちます。
export class CustomError extends Error {
/**
* @param {string} message
* @param {number} [code = 0]
*/
constructor(message, code = 0) {
super();
/**
* @type {string}
* @readonly
*/
this.message = message;
/**
* @type {number}
* @readonly
*/
this.code = code;
/**
* @type {string}
* @readonly
*/
this.name = this.constructor.name;
/**
* @type {string}
* @readonly
*/
this.stack = CustomError.createStack(this);
}
/**
* @return {string}
*/
toString() {
return this.getPrettyMessage();
}
/**
* @return {string}
*/
getPrettyMessage() {
return `${this.message} Code: ${this.code}.`;
}
/**
* @param {CustomError} error
* @return {string}
* @private
*/
static createStack(error) {
return typeof Error.captureStackTrace === 'function'
? Error.captureStackTrace(error, error.constructor)
: (new Error()).stack;
}
}
このコードをテストするには、次のようなものを実行できます。
try {
throw new CustomError('Custom error was thrown!');
} catch (e) {
const message = e.getPrettyMessage();
console.warn(message);
}
CustomError
型の拡張は大歓迎です。拡張タイプに特定の機能を追加したり、既存の機能をオーバーライドすることができます。例えば。
export class RequestError extends CustomError {
/**
* @param {string} message
* @param {string} requestUrl
* @param {number} [code = 0]
*/
constructor(message, requestUrl, code = 0) {
super(message, code);
/**
* @type {string}
* @readonly
*/
this.requestUrl = requestUrl;
}
/**
* @return {string}
*/
getPrettyMessage() {
const base = super.getPrettyMessage();
return `${base} Request URL: ${this.requestUrl}.`;
}
}
Babelを使用していませんが、単純なES6では、次のように動作します。
class CustomError extends Error {
constructor(...args) {
super(...args);
this.name = this.constructor.name;
}
}
REPLからのテスト:
> const ce = new CustomError('foobar');
> ce.name
'CustomError'
> ce.message
'foobar'
> ce instanceof CustomError
true
> ce.stack
'CustomError: foobar\n at CustomError (repl:3:1)\n ...'
ご覧のとおり、スタックにはエラー名とメッセージの両方が含まれています。私は何かを逃しているかどうかはわかりませんが、他のすべての答えは物事を過度に複雑にしているようです。