try/catch and Custom Errors
JavaScript uses try/catch/finally to handle errors gracefully, and lets you define your own error types by extending the built-in Error class.
class ValidationError extends Error {
constructor(message) {
super(message);
this.name = "ValidationError";
}
}
function setAge(age) {
if (age < 0) throw new ValidationError("Age cannot be negative");
return age;
}
try {
setAge(-5);
} catch (err) {
if (err instanceof ValidationError) {
console.log("Invalid input:", err.message);
} else {
throw err; // re-throw anything unexpected
}
} finally {
console.log("Validation attempt finished");
}
Custom error classes let calling code distinguish between different failure types using instanceof, instead of fragile string-matching on err.message. Re-throwing errors you don't recognize (the else branch above) is important — silently swallowing unexpected errors makes bugs much harder to track down later.
finally always runs, whether the try block succeeded, threw, or even returned early — making it the right place for cleanup code like closing a connection or hiding a spinner, regardless of outcome.