I am working on a complex application with different types of errors, services, and domain concepts.
In order to throw "object" errors, there are two different approaches that come to my mind:
- Applying
Object.assign()
to an Error object (easy option if I just need to throw a single or a couple of errors that follows this form):
function f() {
const err = new Error();
Object.assign(err, {
name: "ServiceError",
code: "service/some-string-code",
message: "Some message",
});
throw err;
}
try {
f();
} catch(err) {
console.log(err instanceof Error);
}
- Creating custom errors (extending the Error class)
class MyServiceError extends Error {
constructor(code, message) {
super(message);
this.name = "ServiceError";
this.code = code;
}
}
function f() {
const err = new MyServiceError("service/some-string-code", "Some message");
throw err;
}
try {
f();
} catch(err) {
console.log(err instanceof Error);
console.log(err instanceof MyServiceError);
}
What are the pros and cons between both "custom errors definitions".
Also, if I choose the second approach, it seems that I will need to create multiple CustomError
classes for different domain concepts, services, etc. in order to achieve symmetric code, and a clean architecture... (???) Which in turn I see as reinventing the wheel and adding unnecessary code, because perhaps not all the concepts of the application should need a custom type of exception.
Are both practices considered valid in JavaScript?
Note: throwing objects or string or stuff like that seems really bad to me, as we are not able to get the stack trace, validate instances etc.
// This seems bad to me. Isn't it an anti-pattern?
throw {
code: "",
message: "",
name: ""
}