How to Handle TypeScript Error?

Problem

JavaScript has try...catch syntax for capturing errors in the program, and uses throw to throw “any error.” It is usually recommended to throw the default JS error object🔗 as follows:

// Throw JS error object
try {
throw new Error('Error message');
} catch (error) {
console.error(error.message);
}
// Throw a string
try {
throw 'Error message';
} catch (error) {
console.error(error);
}

How can we correctly identify the type of error in TypeScript? Since “any error” can be thrown, TypeScript treats the error object received in catch as unknown, which makes it difficult for us to accurately determine the error during development.

Solution

Solution 1: Accept Error as Any

In TypeScript, we can treat the error object received in catch as any, which allows us to accept error objects of any type.

try {
throw new Error('Error message');
} catch (error: any) {
console.error(error.message);
}

The problem with this approach is that it is the same as not using TypeScript 😅, as we cannot know the type of error information.

Solution 2: Assert Error Type

Since we know that any error thrown in this code will be an Error object, we can use the as keyword to assert that the caught error must be an Error object. This approach is better because we can ensure that the error object has a type.

However, it is not the best solution, because if the error object is not an Error object, the program will throw an error. We can still throw any type of error in the program, leading to a Runtime Error!

try {
throw new Error('Error message');
} catch (error) {
console.error((error as Error).message);
}
// What if I throw something other than Error? Runtime Error!
try {
throw 'Hello World';
} catch (error) {
console.error((error as Error).message);
}

Best Solution 3: Dynamic Type Checking

The best solution is to check the type of the error object in the catch block, ensuring that the type of the error object is correct. We can use JS’s instanceof🔗 syntax to check if a value is an instance of another class or constructor.

try {
throw new Error('Error message');
} catch (error) {
if (error instanceof Error) {
// This will only execute if error is a JS Error object
console.error(error.message);
}
}

Summary

Avoid using Any or type assertions unnecessarily. Dynamic type checking and handling errors based on the default error object is the best solution. We can even customize error objects based on native error objects, making it easier to identify errors during development. However, this is an extended topic, and you can refer to further reading to learn more.

Further Reading