Home > OS >  Javascript - Create custom errors and make sure that constructor params are valid
Javascript - Create custom errors and make sure that constructor params are valid

Time:11-26

I have defined the following object

const AuthErrorCode = {
   EMAIL_ALREADY_EXISTS: {
      code: "auth/email-already-exists",
      message: "Hello world!"
   },
   ... more error codes
};

And I am implementing a class that extends Error

class AuthError extends Error {
  constructor(code, message = undefined) {
    switch(code) {
      case "EMAIL_ALREADY_EXISTS":
        code = AuthErrorCode[code].code;
        message = message ?? AuthErrorCode[code].message;
        break;

      default:
        throw new Error("Invalid code");
    }

    super(message); 

    Object.assign(this, {
      code,
      name: "AuthError",
    });
  }
}

which is supposed to receive a code and an optional custom message.

This class has to check that the given code is in the AuthErrorCode object (EMAIL_ALREADY_EXISTS || "auth/email-already-exists" are valid). If it is not inside it, then some kind of feedback should be displayed to the programmer (an error or something). I mean, I need to make sure that the code is a valid AuthErrorCode, because if not, the class is being used incorrectly.

How can I do that? Is it possible?

For example, this code must fail:

throw new AuthError("auth/some-invented-code", "Hello world!");

Example of correct use:

throw new AuthError("EMAIL_ALREADY_EXISTS", "Hello world!");
throw new AuthError("auth/email-already-exists");

CodePudding user response:

There's a way but ultimately I think it's bad design.

If you already know the set of valid values why not simply expose factory functions for every error types?

e.g.

// Assume encapsulated in a module

class AuthError extends Error {
  constructor(message, code) {
    super(message);
    this.code = code;
  }
}

// This would get exported (factory methods for errors)
const authErrors = Object.freeze({
  emailAlreadyExists(message = 'Hello world!') {
    return new AuthError('auth/email-already-exists', message);
  }

   // other error types
});

// Client usage
throw authErrors.emailAlreadyExists('email already registered');
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

Alternatively you could create an explicit exception class per error type whic is perhaps more aligned with the Open-Closed Principle:

// Assume encapsulated in a module

class AuthError extends Error {
  constructor(message, code) {
    super(message);
    this.code = code;
  }
}

// Export this
class EmailAdreadyExists extends AuthError {
  constructor(message = "Hello world!") {
    super(message, "auth/email-already-exists");
  }
}

// Client usage
throw new EmailAdreadyExists("email already registered");
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related