Extension de L'erreur en Javascript avec la syntaxe ES6 et Babel
J'essaie d'étendre L'erreur avec ES6 et Babel. Ce n'est pas le travail.
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
L'objet D'erreur n'obtient jamais le bon jeu de messages.
Maintenant, j'ai vu quelques solutions sur SO ( par exemple ici), mais elles semblent toutes très un-ES6-Y. comment le faire d'une manière agréable, ES6? (Cela fonctionne dans Babel)
11 réponses
Basé sur la réponse DE Karel Bílek, je ferais un petit changement à la 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);
Cela imprimera MyError
dans la pile, et non le générique Error
.
Il ajoutera également le message d'erreur à la trace de la pile-qui manquait dans L'exemple de Karel.
Il utilisera également captureStackTrace
s'il est disponible.
Avec Babel 6, vous avez besoin d' transformer-builtin-étendre (npm) pour que cela fonctionne.
Combinant cette réponse, cette réponse et ce code, j'ai fait ce petit "aide" de la classe, qui semble bien fonctionner.
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);
Pour finalement mettre cela au repos. Dans Babel 6, il est explicite que les développeurs ne supportent pas s'étendant à partir de built in. Bien que cette astuce ne aider avec des choses comme Map
, Set
, etc. cela fonctionne pour Error
. Ceci est important car l'une des idées fondamentales d'un langage qui peut lancer une exception est d'autoriser des erreurs personnalisées. Ceci est doublement important car les promesses deviennent plus utiles car elles sont conçues pour rejeter une erreur .
La triste vérité est vous encore besoin d'effectuer cela à l'ancienne dans ES2015.
Modèle D'erreur personnalisé
class MyError {
constructor(message) {
this.name = 'MyError';
this.message = message;
this.stack = new Error().stack; // Optional
}
}
MyError.prototype = Object.create(Error.prototype);
D'autre part, il existe un plugin pour Babel 6 pour permettre cela.
Https://www.npmjs.com/package/babel-plugin-transform-builtin-extend
Mise à jour: (à partir de 2016-09-29) après quelques tests, il semble que babel.io ne tient pas correctement compte de toutes les affirmations (s'étendant à partir d'une erreur étendue personnalisée). Mais dans Braise.L'erreur d'extension js fonctionne comme prévu: https://ember-twiddle.com/d88555a6f408174df0a4c8e0fd6b27ce
Edit: dernières modifications de Tapuscrit 2.1
L'extension des éléments intégrés tels que Error, Array et Map peut ne plus fonctionner.
En tant que recommandation, vous pouvez ajuster manuellement le prototype immédiatement après tout super(...) appeler.
L'édition de la réponse originale de Lee Benson fonctionne un peu pour moi. Cela ajoute également stack
et des méthodes supplémentaires de la classe ExtendableError
à l'instance.
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);
, Avec les derniers changements de babel 6, je trouve transformer-builtin-étendre ne fonctionne plus. J'ai fini par utiliser cette approche mixte:
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;
Et
import MyError from './MyError';
export default class MyChildError extends MyError {
constructor (message) {
super(message);
}
}
En conséquence, tous ces tests passent:
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';
}
}
Il N'y a pas besoin de
this.stack = (new Error()).stack;
truc grâce àsuper()
appel.
Bien que les codes ci-dessus ne puissent pas afficher la trace de la pile à moins que this.stack = (new Error()).stack;
ou Error.captureStackTrace(this, this.constructor.name);
ne soient invoqués dans Babel. OMI, c'est peut-être un problème ici.
En fait, la trace de pile peut être sortie sous Chrome console
et Node.js v4.2.1
avec ces extraits de code.
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);
Sortie de 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)
Sortie de 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
En plus de la réponse @zangw, vous pouvez définir vos erreurs comme ceci:
'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');
Qui lancera le nom, le message et la stacktrace corrects:
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
J'essaie d'étendre L'erreur avec ES6
Cette syntaxe class MyError extends Error {…}
est correcte.
Notez que les transpilers ont toujours des problèmes avec l'héritage des objets intégrés. Dans votre cas,
var err = super(m);
Object.assign(this, err);
Semble résoudre le problème.
Compte tenu de cela, la réponse acceptée ne fonctionne plus, vous pouvez toujours utiliser une usine comme alternative ( 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);
Comme le mentionne @sukima, vous ne pouvez pas étendre js natif. La question du PO ne peut pas être répondue.
Similaire à la réponse de Melbourne2991 , j'ai plutôt utilisé une usine, mais j'ai suivi la recommandation de MDN pour les types d'erreur client .
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;
}
N'utilisant pas Babel, mais en clair ES6, ce qui suit semble bien fonctionner pour moi:
class CustomError extends Error {
constructor(...args) {
super(...args);
this.name = this.constructor.name;
}
}
Test de 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 ...'
Comme vous pouvez le voir, la pile contient à la fois le nom de l'erreur et le message. Je ne suis pas sûr de manquer quelque chose, mais toutes les autres réponses semblent trop compliquer les choses.