Расширение ошибки в Javascript с помощью синтаксиса ES6 & Babel
Я пытаюсь расширить ошибку с 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
объект ошибки никогда не получает правильный набор сообщений.
теперь я видел несколько решений на SO (например тут), но все они кажутся очень не-ES6-y. как это сделать в хорошем, ES6 способе? (То есть работает в Вавилоне)
11 ответов:
основываясь на ответе Карела Билека, я бы внес небольшое изменение в
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
.Он также добавит сообщение об ошибке в трассировку стека, которая отсутствовала в Примере Карела.
Он также будет использовать
captureStackTrace
если он доступен.С Бабелем 6, вам нужно transform-builtin-extend (npm) для этой работы.
объединение ответ,ответ и код, Я сделал этот небольшой вспомогательный класс, который, кажется, работает нормально.
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);
чтобы, наконец, положить этому конец. В Babel 6 явно, что разработчики не поддерживают расширение от встроенного. Хотя это трюк не будет помощь с такими вещами, как
Map
,Set
и т. д. это действительно работает дляError
. Это важно, поскольку одна из основных идей языка, который может вызвать исключение, - разрешить пользовательские ошибки. Это вдвойне важно, поскольку обещания становятся более полезными, поскольку они предназначены для отклонить Ошибка.печальная правда заключается в том, что вам все еще нужно выполнить это по-старому в ES2015.
пользовательский шаблон ошибка
class MyError { constructor(message) { this.name = 'MyError'; this.message = message; this.stack = new Error().stack; // Optional } } MyError.prototype = Object.create(Error.prototype);
С другой стороны, есть плагин для Babel 6, чтобы позволить это.
https://www.npmjs.com/package/babel-plugin-transform-builtin-extend
обновление: (по состоянию на 2016-09-29) после некоторых испытаний оказывается, что babel.io не учитывает должным образом все утверждения (расширение от пользовательской расширенной ошибки). Но в Эмбер.Ошибка расширения JS работает как ожидалось:https://ember-twiddle.com/d88555a6f408174df0a4c8e0fd6b27ce
Edit: нарушение изменений в Typescript 2.1
расширение встроенных модулей, таких как ошибка, массив и карта, может больше не работать.
в качестве рекомендации, вы можете вручную настроить прототип сразу после любой супер(...) телефонные переговоры.
редактирование оригинального ответа ли Бенсона немного работает для меня. Это также добавляет
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 {} 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);
вызывается в Бабель. ИМО, это может быть одна проблема здесь.на самом деле, трассировка стека может быть выход под
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');
который будет бросает правильное имя, сообщение и stacktrace:
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);
как упоминает @sukima, вы не можете расширить собственный JS. На вопрос ОП ответить невозможно.
аналогично 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; }
не используя 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 ...'
Как вы можете видеть, стек содержит как имя ошибки, так и сообщение. Я не уверен, что что-то упускаю, но все остальные ответы, похоже, слишком усложняют ситуацию.