Ich versuche, Error mit ES6 und Babel zu erweitern. Es klappt nicht.
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
Das Error-Objekt erhält nie die richtige Nachricht.
Versuchen Sie es in Babel REPL .
Jetzt habe ich einige Lösungen auf SO ( zum Beispiel hier ) gesehen, aber alle scheinen sehr un-ES6-y zu sein. Wie mache ich das auf eine schöne ES6-Art? (Das funktioniert in Babel)
Basierend auf der Antwort von Karel Bílek würde ich die constructor
etwas ändern:
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);
Dadurch wird MyError
im Stapel und nicht die generische Error
ausgegeben.
Die Fehlermeldung wird außerdem der Stack-Ablaufverfolgung hinzugefügt, die in Karels Beispiel nicht vorhanden war.
Es wird auch captureStackTrace
verwendet, falls verfügbar.
Mit Babel 6 benötigen Sie transform-builtin-extend ( npm ), damit dies funktioniert.
diese Antwort kombinieren , diese Antwort und diesen Code Ich habe diese kleine "Helfer" -Klasse gemacht, die scheint gut zu funktionieren.
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);
Um dies endlich zur Ruhe zu bringen. In Babel 6 ist es ausdrücklich so, dass die Entwickler keine Unterstützung vom eingebauten aus erweitern. Obwohl dieser Trick keine Unterstützung bei Dingen wie Map
hilft , Set
usw. funktioniert für Error
. Dies ist wichtig, da eine der Kernideen einer Sprache, die eine Ausnahme auslösen kann, darin besteht, benutzerdefinierte Fehler zuzulassen. Dies ist doppelt wichtig, da Versprechen nützlicher werden, da sie darauf ausgelegt sind, einen Fehler zurückzuweisen .
Die traurige Wahrheit ist, dass Sie dies in ES2015 noch auf die alte Weise durchführen müssen.
class MyError {
constructor(message) {
this.name = 'MyError';
this.message = message;
this.stack = new Error().stack; // Optional
}
}
MyError.prototype = Object.create(Error.prototype);
Auf der anderen Seite gibt es ein Plugin für Babel 6, um dies zu ermöglichen.
https://www.npmjs.com/package/babel-plugin-transform-builtin-extend
Update: (Stand 29.09.2016) Nach einigen Tests scheint es, dass babel.io nicht alle Asserts korrekt berücksichtigt (von a ausgehend) Benutzerdefinierter erweiterter Fehler). Aber in Ember.JS funktioniert der Erweiterungsfehler wie erwartet: https://ember-twiddle.com/d88555a6f408174df0a4c8e0fd6b27ce
Edit: Änderungen in TypeScript 2.1 brechen
Das Erweitern von integrierten Inhalten wie Error, Array und Map funktioniert möglicherweise nicht mehr.
Als Empfehlung können Sie den Prototyp unmittelbar nach einem Superaufruf (...) manuell anpassen.
Das Bearbeiten von Lee Bensons Originalantwort funktioniert ein bisschen für mich. Dies fügt der Instanz auch stack
und zusätzliche Methoden der ExtendableError
-Klasse hinzu.
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);
Mit den neuesten Änderungen in Babel 6 finde ich transform-builtin-extend funktioniert nicht mehr. Ich habe diesen gemischten Ansatz verwendet:
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;
und
import MyError from './MyError';
export default class MyChildError extends MyError {
constructor (message) {
super(message);
}
}
Als Ergebnis bestehen alle diese Tests:
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';
}
}
Dank
this.stack = (new Error()).stack;
-Aufruf ist keinsuper()
-Trick erforderlich.
Die obigen Codes können den Stack-Trace jedoch nur ausgeben, wenn this.stack = (new Error()).stack;
oder Error.captureStackTrace(this, this.constructor.name);
in Babel aufgerufen wird. IMO, es ist vielleicht ein Thema hier.
Tatsächlich kann der Stack-Trace mit diesen Code-Snippets unter Chrome console
und Node.js v4.2.1
ausgegeben werden.
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);
Ausgabe von 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)
Ausgabe von 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
Zusätzlich zur @Zangw-Antwort können Sie Ihre Fehler folgendermaßen definieren:
'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');
was den korrekten Namen, die Nachricht und den Stacktrace auslöst:
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
Ich versuche, Error mit ES6 zu erweitern
Diese class MyError extends Error {…}
-Syntax ist korrekt.
Beachten Sie, dass Transpiler immer noch Probleme haben, von eingebauten Objekten zu erben. In Ihrem Fall,
var err = super(m);
Object.assign(this, err);
scheint das Problem zu beheben.
Da die akzeptierte Antwort nicht mehr funktioniert, können Sie alternativ immer eine Fabrik verwenden ( 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);
Das funktioniert bei mir:
/**
* @class AuthorizationError
* @extends {Error}
*/
export class AuthorizationError extends Error {
message = 'UNAUTHORIZED';
name = 'AuthorizationError';
}
Wie @sukima erwähnt, können Sie native JS nicht erweitern. Die Frage des OP kann nicht beantwortet werden.
Ähnlich wie in Melbourne2991s Antwort habe ich eher eine Fabrik verwendet, folgte aber der Empfehlung von MDN für Kundenfehlertypen .
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;
}
Ich bevorzuge eine stärkere Syntax als oben beschrieben. Zusätzliche Methoden bei error type helfen Ihnen dabei, console.log
oder etwas anderes zu erstellen.
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;
}
}
Um diesen Code zu testen, können Sie etwas Ähnliches ausführen:
try {
throw new CustomError('Custom error was thrown!');
} catch (e) {
const message = e.getPrettyMessage();
console.warn(message);
}
Die Erweiterung von CustomError
ist erwünscht. Es ist möglich, dem erweiterten Typ bestimmte Funktionen hinzuzufügen oder vorhandene zu überschreiben. Zum Beispiel.
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}.`;
}
}
Ich benutze Babel nicht, aber in ES6 scheint das Folgende gut zu funktionieren:
class CustomError extends Error {
constructor(...args) {
super(...args);
this.name = this.constructor.name;
}
}
Testen von 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 ...'
Wie Sie sehen, enthält der Stack sowohl den Fehlernamen als auch die Fehlermeldung. Ich bin nicht sicher, ob mir etwas fehlt, aber alle anderen Antworten scheinen die Dinge zu komplizieren.