How to type an error in try-catch block
5 min read
TL;DR: TypeScript catch clause variables can now be typed as unknown for better type safety since version 4.0.
Do you know how to handle or type an error in TS in try-catch block
But before going into catch block let's first see what is exception and its types
In TypeScript, an exception refers to an unexpected or exceptional situation that occurs during the execution of a program, causing the normal flow of control to be disrupted. When an exception occurs, it typically results in the termination of the current operation or function and triggers a process known as exception handling.
In TypeScript, exceptions can broadly be categorised into two types: user-defined exceptions and built-in exceptions.
User-defined exceptions: These are exceptions that developers define themselves within their TypeScript code. They can create custom error classes or structures to represent specific error scenarios that might occur within their application. For example, if you're building a banking application, you might define a custom exception class called
InsufficientFundsError
to represent situations where a user tries to withdraw more money than they have in their account.Built-in exceptions: These are exceptions that are part of the JavaScript or TypeScript language itself, or provided by libraries and frameworks. Some common built-in exceptions include
TypeErrorSyntaxErrorRangeErrorReferenceError
orNetworkError
These built-in exceptions are part of the JavaScript runtime environment and are thrown automatically under certain conditions.
we use try-catch block to handle exception as:
function logError(error: Error) {
// LOG ERROR WHERE EVER YOU WANT maybe server
console.log(error.message);
}
function run() {
try {
// YOUR CODE
// Simulating error by throwing it
throw new Error("Throwing error")
} catch (e) {
// HANDLE EXCEPTION
logError(e);
}
}
run();
But what exactly is the type of e in catch clause
. Is it Error
, any
or something else
Before Typescript 4.0
Before Typescript 4.0 catch clause variables were any
by default.
It means you can call do anything with that e
variable as you can see below. It is like we are writing JS code without any type safety.
function run() {
try {
// YOUR CODE
throw new Error("Throwing error")
} catch (e) {
console.log(e.toUpperCase());
e++;
e.method()
}
}
run();
If you execute above code then it will throw error as below if you try to do invalid operations because e
is typed as any
and you can do anything with it. This code is totally unsafe and can leads to undesirable result.
After Typescript 4.0
But from v4.0 Typescript allow us to specify the type of catch
clause variable as unknown
.
That means you can specify unknown
in place of any
.
also, with Typescript 4.0 you have the ability to make your catch clause variable unknown by default with useUnknownInCatchVariables
flag.
unknown
is safer than any
because it reminds us that we need to perform some sorts of type-checks before operating on our values.Instead of saying any
for the type of the error you caught (which means TypeScript won't really check what type of error it is), you can now use unknown
.
Using unknown
is a bit like saying, "Hey, TypeScript, I'm not sure what type of error I'm dealing with here." It's a reminder to you, the developer, that you should be careful and check what kind of data you're dealing with before you do anything with it.
So, TypeScript is nudging us to be more careful and make sure we're doing the right checks before we use the error data. This helps prevent unexpected problems in our code and makes it safer overall.
So if you try to do any operation with catch
clause variable then Typescript will tell you upfront that you have to narrow down your type to perform operation.
Also, there is no guarantee that the error thrown is always subtype of Error
. You can also throw exception manually like.
function run() {
try {
// YOUR CODE
throw "Throwing string"
} catch (e) {
console.log(typeof e);
}
}
run();
So problem is you don't know what exactly is type of e
here, so all you have to do is to narrow it down using type guards
and then perform operation.
So the above code will now be more type safe with unknown because you cannot perform any operation on e
without narrowing down its type
function run() {
try {
// YOUR CODE
} catch (e) {
if (typeof e === "string") {
console.log(e.toUpperCase());
}
if (typeof e === "number") {
e++;
}
if(typeof e === "object" && "method" in e && typeof e.method === "function") {
e.method();
}
}
}
run();
Since you are narrowing type of e
and then performing operation on it which will make our code type-safe.
If you want to dive into the change then you view this PR
Hope you learn something new 👍