JavaScript Custom Error

JavaScript provides built-in error handling capabilities through standard error types like Error, TypeError, SyntaxError, and others.

However, in complex applications, there are scenarios where these built-in error types may not be sufficient to describe the nature of errors accurately. This is where custom errors come into play.

Custom errors allow developers to create specific error types that provide more detailed and meaningful error messages tailored to the application's context.

What Are Custom Errors?

Custom errors are user-defined error types that extend the built-in Errorclass.

By creating custom error classes, developers can encapsulate additional information and context about the error, making debugging and error handling more efficient.

Creating a Custom Error

To create a custom error, you need to extend the Errorclass.

Here’s a basic example:


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

try{ 
  throw new CustomError("Something went wrong!");
}catch(error){
  console.error(error.name); // CustomError
  console.error(error.message); // Something went wrong!
}
            

In the above example, CustomErroris a new error type that inherits from the built-in Errorclass.

The, superfunction is used to call the constructor of the parent Errorclass.

Example


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

try{ 
  throw new CustomError("Something went wrong!");
}catch(error){
  console.error(error.name); // CustomError
  console.error(error.message); // Something went wrong!
}

Adding Properties to Custom Errors

Custom errors can be enhanced by adding properties that provide more context about the error.

This is particularly useful for debugging and logging purposes.

Example with Additional Properties


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

try{ 
  throw new ValidationError("Invalid input", "username'");
}catch(error){
  console.error(`${error.name} on ${error.field}: ${error.message}`); 
  // ValidationError on username: Invalid input
}
            

In the above example, the ValidationErrorclass includes an additional fieldproperty, indicating which field caused the error.

This provides more specific information about the error.

Example


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

try{ 
  throw new ValidationError("Invalid input", "username'");
}catch(error){
  console.error(`${error.name} on ${error.field}: ${error.message}`); 
  // ValidationError on username: Invalid input
}

Custom Error Hierarchies

In large applications, you might need a hierarchy of custom errors to handle different types of errors more precisely.

This can be achieved by creating multiple custom error classes that extend each other.

Example of Custom Error Hierarchy


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

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

class NetworkError extends ApplicationError{
  constructor(message){
  super(message);
    this.name = "NetworkError";
  }
}

try{ 
  throw new ValidationError("Invalid input', 'username'");
  }catch(error){
    if (error instanceof DatabaseError){ 
      console.error("Database Error: "+ error.message);
    }else if (error instanceof NetworkError){ 
      console.error("Network Error: "+ error.message);
    }else {
      console.log("Application Error: "+ error.message);
    }
}
            

In the above example, the DatabaseErrorand NetworkError both extend both extendcreating a hierarchy of custom errors.

This allows for more specific error handling based on the type of error.

Example


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

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

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

class NetworkError extends ApplicationError{
  constructor(message){
  super(message);
    this.name = "NetworkError";
  }
}

try{ 
  throw new ValidationError("Invalid input', 'username'");
  }catch(error){
    if (error instanceof DatabaseError){ 
      console.error("Database Error: "+ error.message);
    }else if (error instanceof NetworkError){ 
      console.error("Network Error: "+ error.message);
    }else {
      console.log("Application Error: "+ error.message);
    }
}

Custom errors in JavaScript provide a powerful mechanism for enhancing error handling in your applications.

By creating specific error types, adding contextual information, and establishing error hierarchies, you can improve the robustness and maintainability of your code.

Custom errors not only make debugging easier but also enhance the user experience by providing clearer and more informative error messages.

Let's learn about custom error using in the next chapter.