Error handling is a crucial aspect of any programming language, and TypeScript is no exception. Proper error handling allows developers to manage and respond to runtime errors effectively, ensuring that applications remain robust and reliable. In this chapter, we will explore error handling in TypeScript from basic to advanced techniques, providing detailed examples and explanations. Our goal is to cover all aspects of TypeScript error handling, ensuring a comprehensive understanding of the topic.
Errors in programming can be broadly categorized into two types:
TypeScript’s strong typing system helps catch many errors at compile time, but runtime errors still need to be managed using proper error handling techniques.
try...catch StatementThe try...catch statement allows you to catch and handle exceptions that occur during the execution of a block of code.
// Base class
class Person {
constructor(public name: string) {}
}
// Mixin function
function CanEat(Base: TBase) {
return class extends Base {
eat() {
console.log(`${this.name} is eating.`);
}
};
}
// Helper type
type Constructor = new (...args: any[]) => {};
// Using the mixin
class Student extends CanEat(Person) {}
const student = new Student('John');
student.eat(); // Output: John is eating.
try block contains code that might throw an error.catch block handles any errors that occur in the try block.error parameter contains information about the thrown error.
An error occurred: [Error details]
You can throw custom errors using the throw statement. This is useful for creating specific error types for different error conditions.
function validateInput(input: string) {
if (input.trim() === "") {
throw new Error("Input cannot be empty");
}
return input;
}
try {
validateInput("");
} catch (error) {
console.error(error.message); // Output: Input cannot be empty
}
validateInput function throws an error if the input is an empty string.catch block handles the error and logs the error message.
Input cannot be empty
Creating custom error classes helps in defining specific error types and handling them appropriately.
class ValidationError extends Error {
constructor(message: string) {
super(message);
this.name = "ValidationError";
}
}
function validateAge(age: number) {
if (age < 0 || age > 120) {
throw new ValidationError("Age must be between 0 and 120");
}
return age;
}
try {
validateAge(-5);
} catch (error) {
if (error instanceof ValidationError) {
console.error("Validation error:", error.message);
} else {
console.error("Unknown error:", error);
}
}
ValidationError is a custom error class that extends the built-in Error class.validateAge function throws a ValidationError if the age is not between 0 and 120.catch block checks if the error is an instance of ValidationError and handles it accordingly.
Validation error: Age must be between 0 and 120
Handling errors in asynchronous code requires different techniques, especially when using async and await.
async function fetchData(url: string) {
try {
let response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
let data = await response.json();
return data;
} catch (error) {
console.error("Failed to fetch data:", error);
}
}
fetchData("https://api.example.com/data");
fetchData function uses async and await to handle asynchronous operations.try...catch block and handled appropriately.
Failed to fetch data: [Error details]
Promise.catchFor handling errors in promises, you can use the catch method.
function getData(url: string): Promise {
return fetch(url)
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.catch(error => {
console.error("Error fetching data:", error);
});
}
getData("https://api.example.com/data");
getData function returns a promise.catch method of the promise.
Error fetching data: [Error details]
Centralized error handling involves creating a single place to handle all errors, making it easier to manage and log errors consistently.
function handleError(error: Error) {
// Log the error to an external service
console.error("Logging error:", error);
}
try {
throw new Error("Something went wrong");
} catch (error) {
handleError(error);
}
handleError function centralizes error logging.handleError function, ensuring consistent error management.
Logging error: Error: Something went wrong
When working with React, you can use error boundaries to catch errors in the component tree.
import React, { Component, ErrorInfo } from "react";
class ErrorBoundary extends Component {
state = { hasError: false };
static getDerivedStateFromError(error: Error) {
return { hasError: true };
}
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
console.error("Error caught in boundary:", error, errorInfo);
}
render() {
if (this.state.hasError) {
return Something went wrong.
;
}
return this.props.children;
}
}
export default ErrorBoundary;
ErrorBoundary is a React component that catches errors in its child components.
Error caught in boundary: [Error details]
We covered TypeScript error handling in depth, from basic try...catch statements to creating custom error classes and handling asynchronous errors. We also explored best practices, such as centralized error handling and using error boundaries in React. Happy coding !❤️
