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>