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.catch
For 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 !❤️