Расширение ошибки в 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.jsMyError: 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 ...'Как вы можете видеть, стек содержит как имя ошибки, так и сообщение. Я не уверен, что что-то упускаю, но все остальные ответы, похоже, слишком усложняют ситуацию.