Learn how to create custom error types in TypeScript by extending the built-in Error class. Enhance your error handling with specific error conditions and additional information.
In software development, error handling is a crucial aspect that ensures our applications can gracefully handle unexpected situations. While TypeScript provides built-in error handling mechanisms, creating custom error types can significantly enhance the clarity and maintainability of your code. In this section, we’ll explore how to create custom error classes in TypeScript, when to use them, and how they can improve your error handling strategy.
Before diving into the implementation, let’s understand why custom error types are beneficial:
Error
ClassTo create a custom error type in TypeScript, we extend the built-in Error
class. This allows us to leverage the existing error-handling infrastructure while adding our custom logic. Let’s see how this is done with a simple example:
class ValidationError extends Error {
constructor(message: string) {
super(message); // Call the parent class constructor
this.name = "ValidationError"; // Set the error name
}
}
// Usage example
try {
throw new ValidationError("Invalid input provided.");
} catch (error) {
if (error instanceof ValidationError) {
console.error(`Validation Error: ${error.message}`);
} else {
console.error(`General Error: ${error.message}`);
}
}
In this example, we define a ValidationError
class that extends the Error
class. We set the name
property to “ValidationError” to differentiate it from other error types.
Custom errors are particularly useful in the following scenarios:
Custom errors can carry additional information that can be useful for debugging or providing more context. Let’s enhance our ValidationError
example by adding an error code:
class ValidationError extends Error {
errorCode: number;
constructor(message: string, errorCode: number) {
super(message);
this.name = "ValidationError";
this.errorCode = errorCode; // Add an error code
}
}
// Usage example
try {
throw new ValidationError("Invalid input provided.", 1001);
} catch (error) {
if (error instanceof ValidationError) {
console.error(`Validation Error [${error.errorCode}]: ${error.message}`);
} else {
console.error(`General Error: ${error.message}`);
}
}
In this version, we added an errorCode
property to the ValidationError
class. This allows us to provide more specific information about the error, which can be particularly useful for logging or displaying user-friendly messages.
throw
Statements and catch
BlocksCustom errors can be used just like built-in errors in throw
statements and catch
blocks. Here’s a more comprehensive example demonstrating how to use custom errors in a function that validates user input:
class ValidationError extends Error {
errorCode: number;
constructor(message: string, errorCode: number) {
super(message);
this.name = "ValidationError";
this.errorCode = errorCode;
}
}
function validateUserInput(input: string): void {
if (input.trim() === "") {
throw new ValidationError("Input cannot be empty.", 1001);
}
if (input.length < 5) {
throw new ValidationError("Input must be at least 5 characters long.", 1002);
}
// Additional validation logic...
}
// Usage example
try {
validateUserInput("abc");
} catch (error) {
if (error instanceof ValidationError) {
console.error(`Validation Error [${error.errorCode}]: ${error.message}`);
} else {
console.error(`General Error: ${error.message}`);
}
}
In this example, the validateUserInput
function throws a ValidationError
if the input does not meet certain criteria. The catch
block then handles the error, providing specific feedback based on the error type.
Using custom errors encourages clearer error differentiation, allowing you to handle different error types appropriately. For instance, you might choose to log validation errors differently from network errors or display different messages to the user.
To solidify your understanding, try modifying the code examples above. Here are some suggestions:
NetworkError
or DatabaseError
.timestamp
or userFriendlyMessage
.catch
block.Let’s visualize the flow of error handling using a Mermaid.js diagram:
graph TD; A[Start] --> B{Validate Input} B -->|Valid| C[Proceed] B -->|Invalid| D[Throw ValidationError] D --> E{Catch Block} E -->|ValidationError| F[Handle Validation Error] E -->|Other Error| G[Handle General Error] F --> H[Log Error] G --> H H --> I[End]
This diagram illustrates the process of input validation, where a ValidationError
is thrown if the input is invalid, and the error is subsequently handled in the catch block.
For more information on error handling in TypeScript, consider exploring the following resources:
In this section, we’ve explored the concept of custom error types in TypeScript. By extending the built-in Error
class, we can create specific error types that enhance the clarity and maintainability of our code. Custom errors allow us to include additional information, differentiate between error types, and handle errors more effectively. As you continue your TypeScript journey, consider incorporating custom errors into your projects to improve your error-handling strategy.