web-dev-qa-db-fra.com

Comment utiliser instanceof dans une instruction switch

J'utilise des erreurs personnalisées ( es6-error ) me permettant de gérer les erreurs en fonction de leur classe comme suit:

import { DatabaseEntryNotFoundError, NotAllowedError } from 'customError';

function fooRoute(req, res) {
  doSomethingAsync()
    .then(() => {
      // on resolve / success
      return res.send(200);
    })
    .catch((error) => {
      // on reject / failure
      if (error instanceof DatabaseEntryNotFoundError) {
        return res.send(404);
      } else if (error instanceof NotAllowedError) {
        return res.send(400);
      }
      log('Failed to do something async with an unspecified error: ', error);
      return res.send(500);
    };
}

Maintenant, je préférerais utiliser un commutateur pour ce type de flux, avec pour résultat quelque chose comme:

import { DatabaseEntryNotFoundError, NotAllowedError } from 'customError';

function fooRoute(req, res) {
  doSomethingAsync()
    .then(() => {
      // on resolve / success
      return res.send(200);
    })
    .catch((error) => {
      // on reject / failure
      switch (error instanceof) {
        case NotAllowedError:
          return res.send(400);
        case DatabaseEntryNotFoundError:
          return res.send(404);
        default:
          log('Failed to do something async with an unspecified error: ', error);
          return res.send(500);
      }
    });
}

instanceof ne fonctionne pas comme ça cependant. Donc, ce dernier échoue.

Est-il possible de vérifier une instance pour sa classe dans une instruction switch?

31
AlexTes

Une bonne option consiste à utiliser la constructorpropriété de l'objet:

// on reject / failure
switch (error.constructor) {
    case NotAllowedError:
        return res.send(400);
    case DatabaseEntryNotFoundError:
        return res.send(404);
    default:
        log('Failed to do something async with an unspecified error: ', error);
        return res.send(500);
}

Notez que constructor doit correspondre exactement à celui avec lequel l'objet a été créé (supposons que error est une instance de NotAllowedError et NotAllowedError est une sous-classe de Error

  • error.constructor === NotAllowedError est true 
  • error.constructor === Error est false

Cela fait une différence par rapport à instanceof, qui peut également correspondre à la super classe: 

  • error instanceof NotAllowedError est true
  • error instanceof Error est true

Vérifiez cet article intéressant à propos de la propriété constructor.

65
Dmitri Pavlutin

Solution de contournement, à éviter si-sinon. Trouvé ici

switch (true) {
    case error instanceof NotAllowedError: 
        return res.send(400);

    case error instanceof DatabaseEntryNotFoundError: 
        return res.send(404);

    default:
        log('Failed to do something async with an unspecified error: ', error);
        return res.send(500);
}
3
ya_dimon

Une alternative à ce cas de commutateur est simplement d'avoir un champ d'état dans le constructeur d'Error. 

Par exemple, construisez votre erreur comme suit:

class NotAllowedError extends Error {
    constructor(message, status) {
        super(message);
        this.message = message;
        this.status = 403; // Forbidden error code
    }
}

Traitez votre erreur comme suit:

.catch((error) => {
  res.send(error.status);
});
0
Lachlan Young