Beginner’s TypeScript #23

Nhan Nguyen
2 min readJan 15, 2024

Error Message: “X Is Of Type Unknown”

We have a function named somethingDangerous which uses a conditional statement based on Math.random(). If the value from Math.random() exceeds 0.5, the function will throw an error, leading to a roughly 50% chance of failure:

const somethingDangerous = () => {
if (Math.random() > 0.5) {
throw new Error("Oh dear!")
}
}

We use a try-catch block to handle this error. However, there is an error message under error inside of the catch block:

try {
somethingDangerous()
} catch (error: unknown) {
console.log(error.message) // red squiggly line under error
}

// Hovering over `error` shows:
'error' is of type 'unknown'.

We will figure out how to understand why this error is happening and determine what changes you could make in the catch block in order to correctly log the error message.

👉 Sulution

The unknown type implies that the value contained in the error could be anything.

However, it is distinct from the any type.

While any turns off type checking on anything it is assigned to, unknown maintains type checking. This means we can narrow the value down to the type we anticipate.

Narrowing with as

One option for fixing this issue is to use as to assert that the error is of type Error:

try {
somethingDangerous()
} catch (error) {
console.log((error as Error).message)
}

Using as tells TypeScript that we know better and it is wrong to think of the error as being unknown.

Conditional Checks

For example, we can use typeof to make sure that error is an object and includes a message property:

try {
somethingDangerous()
} catch (error) {
if (typeof error === "object" && "message" in error) {
console.log(error.message)
} else {
throw error
}
}

This solution works but is not the most elegant.

Instead, we could use instanceof to check if error is an instance of the Error class:

catch (error) {
if (error instanceof Error) {
console.log(error.message)
} else {
throw error
}
}

In this solution, the original error will be thrown if the error does not extend the base Error class. This works well because all types of errors, such as TypeError and SyntaxError, extend the base Error class.

Narrowing is a great way to handle try-catch blocks in TypeScript. If you encounter a situation where x is of type unknown, you can typically use type narrowing to resolve it.

For more complex narrowing, you can use the Zod library (and check out my Zod tutorial).

I hope you found it useful. Thanks for reading. 🙏

Let’s get connected! You can find me on:

--

--