Custom Error Objects in JavaScript

In JavaScript, the Error object is used to represent runtime errors, providing properties like message and name that help describe the error. While JavaScript has built-in error types such as TypeError, SyntaxError, and ReferenceError, sometimes you need to create custom error types to handle specific situations in your code. This can be done by creating custom error objects that extend the native Error class. In this article, we’ll explore how to create and use custom error objects in JavaScript with examples.

1. Creating a Basic Custom Error

You can create a custom error by defining a new class that extends the built-in Error class. This allows you to create errors with specific names and messages tailored to your needs.

Example: Creating a ValidationError class.

          
          class ValidationError extends Error {
              constructor(message) {
                  super(message);
                  this.name = "ValidationError";
              }
          }

          // Usage
          try {
              throw new ValidationError("Invalid input data");
          } catch (error) {
              console.log(error.name); // Outputs: ValidationError
              console.log(error.message); // Outputs: Invalid input data
          }
          
      

In this example, we create a ValidationError class that inherits from Error. When thrown, it includes a custom name and a message.

2. Adding Custom Properties to Custom Errors

Custom error classes can include additional properties to store extra information about the error. This is especially helpful for debugging and providing detailed error information.

Example: Adding a field property to the ValidationError class.

          
          class ValidationError extends Error {
              constructor(message, field) {
                  super(message);
                  this.name = "ValidationError";
                  this.field = field;
              }
          }

          // Usage
          try {
              throw new ValidationError("Invalid input data", "email");
          } catch (error) {
              console.log(error.name); // Outputs: ValidationError
              console.log(error.message); // Outputs: Invalid input data
              console.log(error.field); // Outputs: email
          }
          
      

In this example, we add a field property to the ValidationError class. This property provides more context about which field caused the validation error.

3. Creating Multiple Custom Error Types

In some cases, it is beneficial to create multiple custom error classes to handle different error scenarios. For example, you might have a ValidationError for input validation and a DatabaseError for database-related issues.

Example: Defining ValidationError and DatabaseError classes.

          
          class ValidationError extends Error {
              constructor(message) {
                  super(message);
                  this.name = "ValidationError";
              }
          }

          class DatabaseError extends Error {
              constructor(message) {
                  super(message);
                  this.name = "DatabaseError";
              }
          }

          // Usage
          try {
              throw new DatabaseError("Failed to connect to the database");
          } catch (error) {
              console.log(error.name); // Outputs: DatabaseError
              console.log(error.message); // Outputs: Failed to connect to the database
          }
          
      

In this example, we create two custom error classes: ValidationError and DatabaseError. Each class has a unique name property, making it easy to differentiate between different error types.

4. Using Custom Errors in Functions

Custom errors are often thrown within functions to handle specific cases or invalid conditions. You can use try and catch blocks to manage these errors appropriately.

Example: Using ValidationError in a function.

          
          function validateUser(user) {
              if (!user.name) {
                  throw new ValidationError("Name is required", "name");
              }
              if (user.age < 18) {
                  throw new ValidationError("User must be at least 18 years old", "age");
              }
              return "User is valid";
          }

          // Usage
          try {
              validateUser({ age: 16 });
          } catch (error) {
              console.log(error.name); // Outputs: ValidationError
              console.log(error.message); // Outputs: User must be at least 18 years old
              console.log(error.field); // Outputs: age
          }
          
      

In this example, the validateUser function throws a ValidationError if a user’s name is missing or age is below 18. The catch block can handle these errors and access the additional information provided by the field property.

5. Checking for Custom Errors

When catching errors, you can check if the error is an instance of a specific custom error class. This allows you to handle different error types separately.

Example: Checking for ValidationError and DatabaseError separately.

          
          try {
              throw new DatabaseError("Connection timed out");
          } catch (error) {
              if (error instanceof ValidationError) {
                  console.log("Validation error:", error.message);
              } else if (error instanceof DatabaseError) {
                  console.log("Database error:", error.message);
              } else {
                  console.log("General error:", error.message);
              }
          }
          
      

In this example, the catch block uses instanceof to determine the error type, allowing each type of error to be handled differently.

Conclusion

Creating custom error objects in JavaScript enables you to manage specific types of errors in a clear and organized way. By extending the Error class, you can create error types with custom properties and handle each error scenario appropriately. Using custom error objects improves the readability of your code and enhances error handling, making your applications more robust and easier to debug.





Advertisement