How to use instanceof in a switch statement

JavascriptError HandlingEcmascript 6

Javascript Problem Overview


I use custom errors (es6-error) allowing me to handle errors based on their class like so:

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);
    };
}

Now I'd rather use a switch for this type of flow, resulting in something like:

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 doesn't work like that however. So the latter fails.

Is there any way to check an instance for its class in a switch statement?

Javascript Solutions


Solution 1 - Javascript

A good option is to use the constructor property of the object:

// 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);
}

Notice that the constructor must match exactly with the one that object was created (suppose error is an instance of NotAllowedError and NotAllowedError is a subclass of Error):

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

This makes a difference from instanceof, which can match also the super class:

  • error instanceof NotAllowedError is true
  • error instanceof Error is true

Check this interesting post about constructor property.

Solution 2 - Javascript

Workaround, to avoid if-else. Found here

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);
}

Solution 3 - Javascript

An alternative to this switch case is to just have a status field in the Error's constructor.

For Example, build your error like so:

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

Handle your error like so:

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionalextesView Question on Stackoverflow
Solution 1 - JavascriptDmitri PavlutinView Answer on Stackoverflow
Solution 2 - Javascriptya_dimonView Answer on Stackoverflow
Solution 3 - JavascriptLachlan YoungView Answer on Stackoverflow