Comment créer une erreur personnalisée en JavaScript?

216

Pour une raison quelconque, il semble que la délégation de constructeur ne fonctionne pas dans l'extrait de code suivant:

function NotImplementedError() { 
  Error.apply(this, arguments); 
}
NotImplementedError.prototype = new Error();

var nie = new NotImplementedError("some message");
console.log("The message is: '"+nie.message+"'")

L'exécution de cela donne The message is: ''. Avez-vous des idées sur la raison ou s'il existe un meilleur moyen de créer une nouvelle Errorsous-classe? Y a-t-il un problème avec applyle Errorconstructeur natif que je ne connais pas?

cdleary
la source
Est-ce que nie instance de l'assertion NotImplementedError fonctionne après vos modifications? Je pensais que pour que cela fonctionne, vous devez définir explicitement NotImplementedError.prototype.constructor.
jayarjo
La prochaine fois, veuillez déchirer tout le code superflu qui n'est pas nécessaire pour démontrer votre problème. De plus, wtc est js.jar? Est-ce nécessaire pour reproduire le problème?
BT
2
Modifié cette question afin qu'elle soit compréhensible en 10 secondes plutôt qu'en 10 minutes
BT
J'ai créé une bibliothèque d'héritage / classe qui hérite correctement des types d'erreur: github.com/fresheneesz/proto
BT
1
jsfiddle pour quelques-unes des meilleures réponses.
Nate

Réponses:

194

Mettez à jour votre code pour affecter votre prototype au prototype Error.prototype et l'instanceof et vos assertions fonctionnent.

function NotImplementedError(message) {
    this.name = "NotImplementedError";
    this.message = (message || "");
}
NotImplementedError.prototype = Error.prototype;

Cependant, je voudrais simplement jeter votre propre objet et vérifier la propriété name.

throw {name : "NotImplementedError", message : "too lazy to implement"}; 

Modifier en fonction des commentaires

Après avoir regardé les commentaires et essayé de me rappeler pourquoi j'attribuerais un prototype à la Error.prototypeplace de new Error()Nicholas Zakas dans son article , j'ai créé un jsFiddle avec le code ci-dessous:

function NotImplementedError(message) {
  this.name = "NotImplementedError";
  this.message = (message || "");
}
NotImplementedError.prototype = Error.prototype;

function NotImplementedError2(message) {
  this.message = (message || "");
}
NotImplementedError2.prototype = new Error();

try {
  var e = new NotImplementedError("NotImplementedError message");
  throw e;
} catch (ex1) {
  console.log(ex1.stack);
  console.log("ex1 instanceof NotImplementedError = " + (ex1 instanceof NotImplementedError));
  console.log("ex1 instanceof Error = " + (ex1 instanceof Error));
  console.log("ex1.name = " + ex1.name);
  console.log("ex1.message = " + ex1.message);
}

try {
  var e = new NotImplementedError2("NotImplementedError2 message");
  throw e;
} catch (ex1) {
  console.log(ex1.stack);
  console.log("ex1 instanceof NotImplementedError2 = " + (ex1 instanceof NotImplementedError2));
  console.log("ex1 instanceof Error = " + (ex1 instanceof Error));
  console.log("ex1.name = " + ex1.name);
  console.log("ex1.message = " + ex1.message);
}

La sortie de la console était la suivante.

undefined
ex1 instanceof NotImplementedError = true
ex1 instanceof Error = true
ex1.name = NotImplementedError
ex1.message = NotImplementedError message
Error
    at window.onload (http://fiddle.jshell.net/MwMEJ/show/:29:34)
ex1 instanceof NotImplementedError2 = true
ex1 instanceof Error = true
ex1.name = Error
ex1.message = NotImplementedError2 message

Cela confirme que le "problème" que j'ai rencontré était la propriété de pile de l'erreur était le numéro de ligne où a new Error()été créé, et non où throw es'est produit. Cependant, cela peut être mieux que d'avoir l'effet secondaire d'une NotImplementedError.prototype.name = "NotImplementedError"ligne affectant l'objet Error.

Aussi, notez avec NotImplementedError2, quand je ne définis pas .nameexplicitement, c'est égal à "Erreur". Cependant, comme mentionné dans les commentaires, car cette version définit le prototype sur new Error(), je pourrais définir NotImplementedError2.prototype.name = "NotImplementedError2"et être OK.

Kevin Hakanson
la source
45
Meilleure réponse, mais prendre Error.prototypedirectement est probablement une mauvaise forme. Si vous souhaitez ajouter plus tard un NotImplementedError.prototype.toStringalias d'objet, il Error.prototype.toStringvaut mieux faire NotImplementedError.prototype = new Error().
cdleary
4
Je suis encore un peu perdu dans toutes ces choses prototypes. Pourquoi dans votre exemple vous attribuez un nom à this.name et non à NotImplementedError.prototype.name? Pouvez-vous répondre s'il vous plaît, c'est crucial pour ma compréhension :)
jayarjo
27
Selon code.google.com/p/chromium/issues/detail?id=228909 subclass.prototype = new Error() est une mauvaise forme. Vous êtes censé utiliser à la subclass.prototype = Object.create(superclass.prototype)place. J'espère que cela pourrait également résoudre le problème de trace de pile.
Gili
8
L'astuce simple pour obtenir une trace de pile significative est de générer une erreur dans le constructeur et d'enregistrer sa pile. Cela donnerait une pile d'appels appropriée + 1 ligne pour le constructeur (c'est un this.stack = new Error().stack;
gain
6
-1; c'est faux. Faire NotImplementedError.prototype = Error.prototype;ne fait pas de instanceoftraiter NotImplementedErrorune sous - classe de Error, il les fait instanceoftraiter exactement comme la même classe. Si vous collez le code ci-dessus dans votre console et essayez, new Error() instanceof NotImplementedErrorvous obtiendrez true, ce qui est clairement faux.
Mark Amery
87

Toutes les réponses ci-dessus sont terriblement horribles - vraiment. Même celui avec 107 ups! La vraie réponse est ici les gars:

Héritage de l'objet Error - où se trouve la propriété de message?

TL; DR:

R. La raison messagen'est pas défini est que Errorest une fonction qui retourne un nouvel objet d'erreur et ne pas manipuler thisd'aucune façon.

B. La façon de faire ce droit est de renvoyer le résultat de la demande du constructeur, ainsi que de définir le prototype de la manière habituelle javascript compliquée:

function MyError() {
    var temp = Error.apply(this, arguments);
    temp.name = this.name = 'MyError';
    this.message = temp.message;
    if(Object.defineProperty) {
        // getter for more optimizy goodness
        /*this.stack = */Object.defineProperty(this, 'stack', { 
            get: function() {
                return temp.stack
            },
            configurable: true // so you can change it if you want
        })
    } else {
        this.stack = temp.stack
    }
}
//inherit prototype using ECMAScript 5 (IE 9+)
MyError.prototype = Object.create(Error.prototype, {
    constructor: {
        value: MyError,
        writable: true,
        configurable: true
    }
});

var myError = new MyError("message");
console.log("The message is: '" + myError.message + "'"); // The message is: 'message'
console.log(myError instanceof Error); // true
console.log(myError instanceof MyError); // true
console.log(myError.toString()); // MyError: message
console.log(myError.stack); // MyError: message \n 
// <stack trace ...>


 
//for EMCAScript 4 or ealier (IE 8 or ealier), inherit prototype this way instead of above code:
/*
var IntermediateInheritor = function() {};
IntermediateInheritor.prototype = Error.prototype;
MyError.prototype = new IntermediateInheritor();
*/

Vous pourriez probablement faire une supercherie pour énumérer toutes les propriétés non énumérables de l' tmperreur pour les définir plutôt que de définir explicitement uniquement stacket message, mais la supercherie n'est pas prise en charge dans ie <9

BT
la source
2
Cette solution fonctionne également pour instancier une erreur personnalisée avec une erreur existante. Si vous utilisez une bibliothèque tierce et souhaitez encapsuler une erreur existante avec votre propre type personnalisé, les autres méthodes ne fonctionnent pas correctement. Pour info, vous pouvez instancier des erreurs vanille en leur passant une erreur existante.
Kyle Mueller
1
vous ne devriez pas return thisdans un constructeur.
Onur Yıldırım
13
J'ai simplifié et amélioré un peu cette approche: jsbin.com/rolojuhuya/1/edit?js,console
Matt Kantor
3
@MattKantor peut-être en faire une réponse? Je pense que j'aime mieux le vôtre.
mpoisot
2
Au lieu de temp.name = this.name = 'MyError', vous pouvez le faire temp.name = this.name = this.constructor.name. De cette façon, cela fonctionnera également pour les sous-classes de MyError.
Jo Liss
45

Dans ES2015, vous pouvez utiliser classpour le faire proprement:

class NotImplemented extends Error {
  constructor(message = "", ...args) {
    super(message, ...args);
    this.message = message + " has not yet been implemented.";
  }
}

Cela ne modifie pas le global Errorprototype, vous permet de personnaliser message, nameet d' autres attributs, et capture correctement la pile. C'est aussi assez lisible.

Bien sûr, vous devrez peut-être utiliser un outil comme babelsi votre code s'exécutera sur des navigateurs plus anciens.

rattray
la source
23

Si quelqu'un est curieux de savoir comment créer une erreur personnalisée et obtenir la trace de la pile:

function CustomError(message) {
  this.name = 'CustomError';
  this.message = message || '';
  var error = new Error(this.message);
  error.name = this.name;
  this.stack = error.stack;
}
CustomError.prototype = Object.create(Error.prototype);

try {
  throw new CustomError('foobar');
}
catch (e) {
  console.log('name:', e.name);
  console.log('message:', e.message);
  console.log('stack:', e.stack);
}
risto
la source
7

Cette section de la norme peut expliquer pourquoi l' Error.applyappel n'initialise pas l'objet:

15.11.1 Le constructeur d'erreur appelé en tant que fonction

Lorsque Error est appelé en tant que fonction plutôt qu'en tant que constructeur, il crée et initialise un nouvel objet Error. Ainsi, l'appel de fonction Error (...) est équivalent à l'expression de création d'objet new Error (...) avec les mêmes arguments.

Dans ce cas, la Errorfonction détermine probablement qu'elle n'est pas appelée en tant que constructeur, elle renvoie donc une nouvelle instance d'erreur plutôt que d'initialiser l' thisobjet.

Les tests avec le code suivant semblent démontrer que c'est en fait ce qui se passe:

function NotImplementedError() { 
   var returned = Error.apply(this, arguments);
   console.log("returned.message = '" + returned.message + "'");
   console.log("this.message = '" + this.message + "'");
}
NotImplementedError.prototype = new Error();

var nie = new NotImplementedError("some message");

La sortie suivante est générée lors de son exécution:

returned.message = 'some message'
this.message = ''
Dave
la source
comment cela pourrait-il être simulé avec une classe d'erreur personnalisée? Par exemple, comment ma classe d'erreur personnalisée peut-elle être utilisée à la fois comme fonction qui crée une instance et comme constructeur?
Lea Hayes
Non, ce n'est pas vrai. S'il renvoyait une nouvelle instance Error, sa propriété msg fonctionnerait.
BT
@BT Comment la propriété msg de la nouvelle instance affecte-t-elle la propriété msg de thisin Error.apply(this, arguments);? Je dis que l'appel à Error ici construit un nouvel objet, qui est jeté; ne pas initialiser l'objet déjà construit auquel est affecté nie.
Dave
@BT J'ai ajouté un exemple de code qui, je l'espère, clarifie ce que j'essayais de dire.
Dave
@Dave J'ai peut-être mal compris le but ici, mais votre NotImplementedErrorimplémentation ne devrait-elle pas retourner la returnedvariable?
blong
7
function InvalidValueError(value, type) {
    this.message = "Expected `" + type.name + "`: " + value;
    var error = new Error(this.message);
    this.stack = error.stack;
}
InvalidValueError.prototype = new Error();
InvalidValueError.prototype.name = InvalidValueError.name;
InvalidValueError.prototype.constructor = InvalidValueError;
Pierre Voisin
la source
3
C'est la meilleure réponse ici. Il est succint et l'exception créée de cette façon se comportera correctement dans toutes les situations. Il préserve également la trace de pile, ce qui est très important dans les applications non triviales. Je remplacerais seulement "prototype = new Error ()" par "prototype = Object.create (Error.prototype)". Pour Node.js, il existe une petite bibliothèque qui fait cela pour vous: npmjs.com/package/node-custom-errors
Lukasz Korzybski
6

J'ai eu un problème similaire à celui-ci. Mon erreur doit être à la instanceoffois ErroretNotImplemented , et elle doit également produire une trace cohérente dans la console.

Ma solution:

var NotImplemented = (function() {
  var NotImplemented, err;
  NotImplemented = (function() {
    function NotImplemented(message) {
      var err;
      err = new Error(message);
      err.name = "NotImplemented";
      this.message = err.message;
      if (err.stack) this.stack = err.stack;
    }
    return NotImplemented;
  })();
  err = new Error();
  err.name = "NotImplemented";
  NotImplemented.prototype = err;

  return NotImplemented;
}).call(this);

// TEST:
console.log("instanceof Error: " + (new NotImplemented() instanceof Error));
console.log("instanceof NotImplemented: " + (new NotImplemented() instanceofNotImplemented));
console.log("message: "+(new NotImplemented('I was too busy').message));
throw new NotImplemented("just didn't feel like it");

Résultat de l'exécution avec node.js:

instanceof Error: true
instanceof NotImplemented: true
message: I was too busy

/private/tmp/t.js:24
throw new NotImplemented("just didn't feel like it");
      ^
NotImplemented: just didn't feel like it
    at Error.NotImplemented (/Users/colin/projects/gems/jax/t.js:6:13)
    at Object.<anonymous> (/Users/colin/projects/gems/jax/t.js:24:7)
    at Module._compile (module.js:449:26)
    at Object.Module._extensions..js (module.js:467:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Module.runMain (module.js:487:10)
    at process.startup.processNextTick.process._tickCallback (node.js:244:9)

L'erreur passe tous les 3 de mes critères, et bien que la stackpropriété ne soit pas standard, elle est prise en charge dans la plupart des navigateurs les plus récents, ce qui est acceptable dans mon cas.

sinisterchipmunk
la source
5

En accédant à Joyent, vous ne devriez pas jouer avec la propriété stack (que je vois dans de nombreuses réponses données ici), car cela aura un impact négatif sur les performances. Voici ce qu'ils disent:

pile: généralement, ne plaisante pas avec ça. Ne l'augmentez même pas. V8 ne le calcule que si quelqu'un lit réellement la propriété, ce qui améliore considérablement les performances pour les erreurs de gestion. Si vous lisez la propriété juste pour l'augmenter, vous finirez par payer le coût même si votre appelant n'a pas besoin de la pile.

J'aime et j'aimerais mentionner leur idée d'envelopper l'erreur d'origine qui est un bon remplacement pour passer sur la pile.

Voici donc comment créer une erreur personnalisée, compte tenu de ce qui précède:

version es5:

function RError(options) {
    options = options || {}; // eslint-disable-line no-param-reassign
    this.name = options.name;
    this.message = options.message;
    this.cause = options.cause;

    // capture stack (this property is supposed to be treated as private)
    this._err = new Error();

    // create an iterable chain
    this.chain = this.cause ? [this].concat(this.cause.chain) : [this];
}
RError.prototype = Object.create(Error.prototype, {
    constructor: {
        value: RError,
        writable: true,
        configurable: true
    }
});

Object.defineProperty(RError.prototype, 'stack', {
    get: function stack() {
        return this.name + ': ' + this.message + '\n' + this._err.stack.split('\n').slice(2).join('\n');
    }
});

Object.defineProperty(RError.prototype, 'why', {
    get: function why() {
        var _why = this.name + ': ' + this.message;
        for (var i = 1; i < this.chain.length; i++) {
            var e = this.chain[i];
            _why += ' <- ' + e.name + ': ' + e.message;
        }
        return _why;
    }
});

// usage

function fail() {
    throw new RError({
        name: 'BAR',
        message: 'I messed up.'
    });
}

function failFurther() {
    try {
        fail();
    } catch (err) {
        throw new RError({
            name: 'FOO',
            message: 'Something went wrong.',
            cause: err
        });
    }
}

try {
    failFurther();
} catch (err) {
    console.error(err.why);
    console.error(err.stack);
    console.error(err.cause.stack);
}

version es6:

class RError extends Error {
    constructor({name, message, cause}) {
        super();
        this.name = name;
        this.message = message;
        this.cause = cause;
    }
    [Symbol.iterator]() {
        let current = this;
        let done = false;
        const iterator = {
            next() {
                const val = current;
                if (done) {
                    return { value: val, done: true };
                }
                current = current.cause;
                if (!val.cause) {
                    done = true;
                }
                return { value: val, done: false };
            }
        };
        return iterator;
    }
    get why() {
        let _why = '';
        for (const e of this) {
            _why += `${_why.length ? ' <- ' : ''}${e.name}: ${e.message}`;
        }
        return _why;
    }
}

// usage

function fail() {
    throw new RError({
        name: 'BAR',
        message: 'I messed up.'
    });
}

function failFurther() {
    try {
        fail();
    } catch (err) {
        throw new RError({
            name: 'FOO',
            message: 'Something went wrong.',
            cause: err
        });
    }
}

try {
    failFurther();
} catch (err) {
    console.error(err.why);
    console.error(err.stack);
    console.error(err.cause.stack);
}

J'ai mis ma solution dans un module, la voici: https://www.npmjs.com/package/rerror

borisdiakur
la source
3

J'aime le faire comme ça:

  • Utilisez le nom pour que toString () lance"{code}: {message}"
  • Renvoie la même chose à super pour qu'elle apparaisse de la même manière dans le stacktrace
  • Attacher du code à error.code car la vérification / l'analyse d'un code est meilleure dans le code que la vérification d'un message, que vous voudrez peut-être localiser par exemple
  • Joindre un message à error.messagecomme alternative àerror.toString()

class AppException extends Error {
  constructor(code, message) {
    const fullMsg = message ? `${code}: ${message}` : code;
    super(fullMsg);
    this.name = code;
    this.code = code;
    this.message = fullMsg;
  }
  
  toString() {
    return this.message;
  }
}

// Just a code
try {
  throw new AppException('FORBIDDEN');
} catch(e) {
  console.error(e);
  console.error(e.toString());
  console.log(e.code === 'FORBIDDEN');
}

// A code and a message
try {
  throw new AppException('FORBIDDEN', 'You don\'t have access to this page');
} catch(e) {
  console.error(e);
  console.error(e.toString());
  console.log(e.code === 'FORBIDDEN');
}

Dominique
la source
2

J'ai juste dû implémenter quelque chose comme ça et j'ai constaté que la pile était perdue dans ma propre implémentation d'erreur. Ce que je devais faire était de créer une erreur factice et de récupérer la pile à partir de cela:

My.Error = function (message, innerException) {
    var err = new Error();
    this.stack = err.stack; // IMPORTANT!
    this.name = "Error";
    this.message = message;
    this.innerException = innerException;
}
My.Error.prototype = new Error();
My.Error.prototype.constructor = My.Error;
My.Error.prototype.toString = function (includeStackTrace) {
    var msg = this.message;
    var e = this.innerException;
    while (e) {
        msg += " The details are:\n" + e.message;
        e = e.innerException;
    }
    if (includeStackTrace) {
        msg += "\n\nStack Trace:\n\n" + this.stack;
    }
    return msg;
}
Jules
la source
Cela ne définit pas le message
BT
2

J'ai utilisé le modèle de constructeur pour créer le nouvel objet d'erreur. J'ai défini la chaîne de prototype telle qu'une Errorinstance. Voir la référence du constructeur MDN Error .

Vous pouvez vérifier cet extrait sur cet essentiel .

LA MISE EN OEUVRE

// Creates user-defined exceptions
var CustomError = (function() {
  'use strict';

  //constructor
  function CustomError() {
    //enforces 'new' instance
    if (!(this instanceof CustomError)) {
      return new CustomError(arguments);
    }
    var error,
      //handles the arguments object when is passed by enforcing a 'new' instance
      args = Array.apply(null, typeof arguments[0] === 'object' ? arguments[0] : arguments),
      message = args.shift() || 'An exception has occurred';

    //builds the message with multiple arguments
    if (~message.indexOf('}')) {
      args.forEach(function(arg, i) {
        message = message.replace(RegExp('\\{' + i + '}', 'g'), arg);
      });
    }

    //gets the exception stack
    error = new Error(message);
    //access to CustomError.prototype.name
    error.name = this.name;

    //set the properties of the instance
    //in order to resemble an Error instance
    Object.defineProperties(this, {
      stack: {
        enumerable: false,
        get: function() { return error.stack; }
      },
      message: {
        enumerable: false,
        value: message
      }
    });
  }

  // Creates the prototype and prevents the direct reference to Error.prototype;
  // Not used new Error() here because an exception would be raised here,
  // but we need to raise the exception when CustomError instance is created.
  CustomError.prototype = Object.create(Error.prototype, {
    //fixes the link to the constructor (ES5)
    constructor: setDescriptor(CustomError),
    name: setDescriptor('JSU Error')
  });

  function setDescriptor(value) {
    return {
      configurable: false,
      enumerable: false,
      writable: false,
      value: value
    };
  }

  //returns the constructor
  return CustomError;
}());

USAGE

Le constructeur CustomError peut recevoir de nombreux arguments pour générer le message, par exemple

var err1 = new CustomError("The url of file is required"),
    err2 = new CustomError("Invalid Date: {0}", +"date"),
    err3 = new CustomError("The length must be greater than {0}", 4),
    err4 = new CustomError("Properties .{0} and .{1} don't exist", "p1", "p2");

throw err4;

Et voici à quoi ressemble l'erreur personnalisée:

Chaîne de prototype d'erreur personnalisée

jherax
la source
Celui qui a voté contre, avez-vous des arguments ou une raison pour voter contre? ou ne comprend tout simplement pas l'intention du code.
jherax du
Je viens de remarquer que j'ai dû accidentellement cliquer sur le bouton downvote lors de la navigation sur cette page sans m'en rendre compte (probablement en naviguant depuis mon téléphone). Je ne l'ai remarqué qu'aujourd'hui en parcourant mon historique. Ce n'était certainement pas intentionnel mais je ne peux pas le défaire car c'est pendant la période de grâce. Vous avez fourni une réponse informative et ne la méritez certainement pas. Si vous effectuez une modification, je annulerai avec plaisir le downvote. Désolé pour ça.
jschr
1

Le constructeur doit être comme une méthode d'usine et retourner ce que vous voulez. Si vous avez besoin de méthodes / propriétés supplémentaires, vous pouvez les ajouter à l'objet avant de le renvoyer.

function NotImplementedError(message) { return new Error("Not implemented", message); }

x = new NotImplementedError();

Mais je ne sais pas pourquoi vous auriez besoin de faire ça. Pourquoi ne pas simplement utiliser new Error...? Les exceptions personnalisées n'ajoutent pas grand-chose en JavaScript (ou probablement dans n'importe quel langage non typé).

pluckyglen
la source
2
Vous devez activer la hiérarchie de type d'erreur ou la valeur d'objet en JavaScript car vous ne pouvez spécifier qu'un seul bloc catch. Dans votre solution, (x instanceof NotImplementedError) est false, ce qui n'est pas acceptable dans mon cas.
cdleary
1

Ceci est bien implémenté dans Cesium DeveloperError:

Sous sa forme simplifiée:

var NotImplementedError = function(message) {
    this.name = 'NotImplementedError';
    this.message = message;
    this.stack = (new Error()).stack;
}

// Later on...

throw new NotImplementedError();
Aram Kocharyan
la source
Cela fonctionne très bien, sauf que la pile contiendra une ligne supplémentaire pour le constructeur d'erreur, ce qui peut être un problème.
SystemParadox
En outre, ne réussit pas le error instanceof Errortest, ce qui peut être utile.
Lauren
1

Voici ma mise en œuvre:

class HttpError extends Error {
  constructor(message, code = null, status = null, stack = null, name = null) {
    super();
    this.message = message;
    this.status = 500;

    this.name = name || this.constructor.name;
    this.code = code || `E_${this.name.toUpperCase()}`;
    this.stack = stack || null;
  }

  static fromObject(error) {
    if (error instanceof HttpError) {
      return error;
    }
    else {
      const { message, code, status, stack } = error;
      return new ServerError(message, code, status, stack, error.constructor.name);
    }
  }

  expose() {
    if (this instanceof ClientError) {
      return { ...this };
    }
    else {
      return {
        name: this.name,
        code: this.code,
        status: this.status,
      }
    }
  }
}

class ServerError extends HttpError {}

class ClientError extends HttpError { }

class IncorrectCredentials extends ClientError {
  constructor(...args) {
    super(...args);
    this.status = 400;
  }
}

class ResourceNotFound extends ClientError {
  constructor(...args) {
    super(...args);
    this.status = 404;
  }
}

Exemple d'utilisation # 1:

app.use((req, res, next) => {
  try {
    invalidFunction();
  }
  catch (err) {
    const error = HttpError.fromObject(err);
    return res.status(error.status).send(error.expose());
  }
});

Exemple d'utilisation # 2:

router.post('/api/auth', async (req, res) => {
  try {
    const isLogged = await User.logIn(req.body.username, req.body.password);

    if (!isLogged) {
      throw new IncorrectCredentials('Incorrect username or password');
    }
    else {
      return res.status(200).send({
        token,
      });
    }
  }
  catch (err) {
    const error = HttpError.fromObject(err);
    return res.status(error.status).send(error.expose());
  }
});
Rafal Enden
la source
0

Au détriment de ne pas pouvoir utiliser instanceof, ce qui suit préserve la trace de pile d'origine et n'utilise aucune astuce non standard.

// the function itself
var fixError = function(err, name) {
    err.name = name;
    return err;
}

// using the function
try {
    throw fixError(new Error('custom error message'), 'CustomError');
} catch (e) {
    if (e.name == 'CustomError')
        console.log('Wee! Custom Error! Msg:', e.message);
    else
        throw e; // unhandled. let it propagate upwards the call stack
}
Gima
la source
tout ce que vous devez faire ici pour pouvoir utiliser instanceof est de lancer un nouveau fixError au lieu de simplement fixError
BT
@BT: Pas avec la fixErrorfonction ci-dessus. L'ajout d'un newlors de son appel ne ferait que créer un objet qui serait jeté.
TJ Crowder
Oh je suppose que je voulais dire "instanceof fixError" - bien sûr alors "instanceof Error" ne fonctionnerait pas .. je suppose que c'est pire ..
BT
0

Une autre alternative, pourrait ne pas fonctionner dans tous les environnements.Au moins assuré que cela fonctionne dans nodejs 0.8 Cette approche utilise un moyen non standard de modifier le prop prop interne

function myError(msg){ 
      var e = new Error(msg); 
      _this = this; 
      _this.__proto__.__proto__ = e;
}
Chandu
la source
0

Si vous utilisez Node / Chrome. L'extrait suivant vous fournira une extension qui répond aux exigences suivantes.

  • err instanceof Error
  • err instanceof CustomErrorType
  • console.log () renvoie [CustomErrorType] lorsqu'il est créé avec un message
  • console.log () renvoie [CustomErrorType: message] lorsqu'il est créé sans message
  • throw / stack fournit les informations au point où l'erreur a été créée.
  • Fonctionne de manière optimale dans Node.JS et Chrome.
  • Passera des vérifications instanceof dans Chrome, Safari, Firefox et IE 8+, mais n'aura pas de pile valide en dehors de Chrome / Safari. Je suis d'accord avec cela car je peux déboguer dans Chrome, mais le code qui nécessite des types d'erreur spécifiques fonctionnera toujours entre les navigateurs. Si vous avez uniquement besoin de Node, vous pouvez facilement supprimer les ifinstructions et vous êtes prêt à partir .

Fragment

var CustomErrorType = function(message) {
    if (Object.defineProperty) {
        Object.defineProperty(this, "message", {
            value : message || "",
            enumerable : false
        });
    } else {
        this.message = message;
    }

    if (Error.captureStackTrace) {
        Error.captureStackTrace(this, CustomErrorType);
    }
}

CustomErrorType.prototype = new Error();
CustomErrorType.prototype.name = "CustomErrorType";

Usage

var err = new CustomErrorType("foo");

Production

var err = new CustomErrorType("foo");
console.log(err);
console.log(err.stack);

[CustomErrorType: foo]
CustomErrorType: foo
    at Object.<anonymous> (/errorTest.js:27:12)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)
    at node.js:906:3

/errorTest.js:30
        throw err;
              ^
CustomErrorType: foo
    at Object.<anonymous> (/errorTest.js:27:12)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)
    at node.js:906:3
Nucléon
la source
0

Ce qui suit a fonctionné pour moi tiré de la documentation officielle de Mozilla Erreur .

function NotImplementedError(message) {
    var instance = new Error(message);
    instance.name = 'NotImplementedError';

    Object.setPrototypeOf(instance, Object.getPrototypeOf(this));
    if (Error.captureStackTrace) {
        Error.captureStackTrace(instance, NotImplementedError);
    }
    return instance;
}

NotImplementedError.prototype = Object.create(Error.prototype, {
    constructor: {
        value: Error,
        enumerable: false,
        writable: true,
        configurable: true
    }
});
Zhunio
la source
-1

Essayez un nouvel objet prototype pour chaque instance du type d'erreur défini par l'utilisateur. Il permet aux instanceofcontrôles de se comporter comme d'habitude et le type et le message sont correctement signalés dans Firefox et V8 (Chome, nodejs).

function NotImplementedError(message){
    if(NotImplementedError.innercall===undefined){
        NotImplementedError.innercall = true;
        NotImplementedError.prototype = new Error(message);
        NotImplementedError.prototype.name = "NotImplementedError";
        NotImplementedError.prototype.constructor = NotImplementedError;

        return new NotImplementedError(message);
    }
    delete NotImplementedError.innercall;
}

Notez qu'une entrée supplémentaire précède la pile sinon correcte.

Augustus Kling
la source
Ça ne marche pas. Essayez: var a = new NotImplementedError('a'), b = new NotImplementedError('b');. Maintenant a instanceof NotImplementedError == falseetb instanceof NotImplementedError == true
jjrv
-1

C'est le moyen le plus rapide de le faire:

    let thisVar = false

    if (thisVar === false) {
            throw new Error("thisVar is false. It should be true.")
    }
jlhs
la source
-3

moyen plus facile. Vous pouvez faire hériter votre objet de l'objet Error. Exemple:

function NotImplementError(message)
{
    this.message = message;
    Error.call();
    Error.call(message);
} 

ce que nous faisons est d'utiliser la fonction call () qui appelle le constructeur de la classe Error, c'est donc fondamentalement la même chose que d'implémenter un héritage de classe dans d'autres langages orientés objet.

Paulo Enmanuel
la source
-3

MDN a un excellent exemple :

try {
  throw new Error('Whoops!');
} catch (e) {
  console.log(e.name + ': ' + e.message);
}
Ronnie Royston
la source