Mastering TypeScript's Advanced Error Handling with Custom Error Classes
Learn how to enhance your error handling in TypeScript by creating custom error classes. This beginner-friendly guide explains why and how to extend built-in errors for cleaner and more maintainable code.
Error handling is a crucial part of building reliable applications. While JavaScript and TypeScript provide basic Error objects, creating custom error classes allows developers to represent different error types clearly and handle them appropriately. In this article, we'll explore how to create and use custom error classes in TypeScript to handle errors more effectively.
Why should you create custom error classes? Imagine you have different kinds of errors such as validation errors, database errors, or network errors. Using generic errors might make it difficult to identify and handle these cases correctly. Custom error classes let you categorize and provide specific details for each error type.
Let's start with creating a simple custom error class in TypeScript. We extend the built-in `Error` class and add a name for easy identification.
class ValidationError extends Error {
constructor(message: string) {
super(message);
this.name = 'ValidationError';
Object.setPrototypeOf(this, ValidationError.prototype); // important for instanceof
}
}
// Example usage:
function validateUsername(username: string) {
if (username.length < 3) {
throw new ValidationError('Username must be at least 3 characters long.');
}
return true;
}
try {
validateUsername('ab');
} catch (error) {
if (error instanceof ValidationError) {
console.error(`Validation Error: ${error.message}`);
} else {
console.error('Unknown error:', error);
}
}Notice the use of `Object.setPrototypeOf(this, ValidationError.prototype);`. This line ensures the custom error works correctly with `instanceof`. Without it, some JavaScript environments may not recognize the error as an instance of your custom class.
You can also add additional properties to your custom errors to provide more context. Here's an example of a `DatabaseError` that includes an error code:
class DatabaseError extends Error {
public code: number;
constructor(message: string, code: number) {
super(message);
this.code = code;
this.name = 'DatabaseError';
Object.setPrototypeOf(this, DatabaseError.prototype);
}
}
function fetchUserFromDB(userId: string) {
// Simulated database error
throw new DatabaseError('User not found in database.', 404);
}
try {
fetchUserFromDB('123');
} catch (error) {
if (error instanceof DatabaseError) {
console.error(`Database Error (${error.code}): ${error.message}`);
} else {
console.error('Unknown error:', error);
}
}Using custom error classes lets you write cleaner error handling code and respond to different error types more precisely. It is particularly helpful when working with complex applications or APIs.
In conclusion, to master advanced error handling in TypeScript, start by creating custom error classes. Remember to extend `Error`, set the correct prototype, and optionally add more error context through properties. This approach will make your application more robust and easier to maintain.