In TypeScript, like in many other programming languages, errors are a natural part of software development. They help us identify and handle issues that arise during the execution of our code. While JavaScript provides built-in error types such as Error, SyntaxError, TypeError, etc., sometimes you might need to define your own custom error classes to better represent specific error conditions in your application.
Custom errors can make your code more readable, maintainable, and easier to debug by providing more context about the nature of the error. In this tutorial, we'll explore how to create and use custom error classes in TypeScript.
Creating a custom error class involves extending the built-in Error class provided by JavaScript. By doing so, you can add additional properties or methods specific to your application's needs. Here’s a step-by-step guide on how to define and use custom errors:
Error class.Let's define a custom error class called UserNotFoundError. This error will be thrown when a user is not found in the system.
1class UserNotFoundError extends Error {2constructor(message?: string) {3super(message || 'User not found');4this.name = 'UserNotFoundError';5}6}
In this example, we've created a class UserNotFoundError that extends the built-in Error class. We've also set the name property to 'UserNotFoundError', which is useful for identifying the type of error.
Now, let's see how you can throw this custom error in your code.
1function getUserById(userId: string): User {2const user = users.find(u => u.id === userId);34if (!user) {5throw new UserNotFoundError(`User with ID ${userId} not found`);6}78return user;9}
In this function, we're trying to find a user by their ID. If the user is not found, we throw a UserNotFoundError with a message indicating that the user was not found.
Finally, let's see how you can catch and handle this custom error.
1try {2const user = getUserById('non-existent-id');3console.log(user);4} catch (error) {5if (error instanceof UserNotFoundError) {6console.error(error.message); // Output: User with ID non-existent-id not found7} else {8console.error('An unexpected error occurred:', error);9}10}
In this example, we're using a try-catch block to handle the UserNotFoundError. If the error is an instance of UserNotFoundError, we log the specific message. Otherwise, we log a generic error message.
You can also add custom properties to your error class to provide more context.
1class UserNotFoundError extends Error {2userId: string;34constructor(userId: string) {5super(`User with ID ${userId} not found`);6this.name = 'UserNotFoundError';7this.userId = userId;8}9}
Now, when you throw the UserNotFoundError, you can pass the user ID as an argument.
1function getUserById(userId: string): User {2const user = users.find(u => u.id === userId);34if (!user) {5throw new UserNotFoundError(userId);6}78return user;9}
And when catching the error, you can access the custom property.
1try {2const user = getUserById('non-existent-id');3console.log(user);4} catch (error) {5if (error instanceof UserNotFoundError) {6console.error(`User with ID ${error.userId} not found`);7} else {8console.error('An unexpected error occurred:', error);9}10}
In the next section, we'll dive into debugging TypeScript code. You'll learn how to use tools like breakpoints, debuggers, and logging techniques to identify and fix issues in your applications.
By mastering custom errors and debugging, you'll be well-equipped to handle a wide range of scenarios that arise during software development.