Solve - Object is of type 'unknown' Error in TypeScript

avatar

Borislav Hadzhiev

Fri Feb 25 20223 min read

banner

Photo by Wira Dyatmika

Solve - Object is of type 'unknown' Error in TypeScript #

The "Object is of type unknown" error occurs when we try to access a property on a value that has a type of unknown. To solve the error, use a type guard to narrow down the type of the object before accessing a property, e.g. if (err instanceof Error) {}.

object is of type unknown

Here is an example of how the error occurs:

index.ts
async function fetchData() { try { await Promise.resolve(42); } catch (err) { // 👈️ err is type unknown // ⛔️ Error: object is of type unknown console.log(err.message); } }

We cannot guarantee that the error in the catch block will be an Error instance ahead of time, so TypeScript sets its type to unknown to avoid any unexpected runtime errors.

To get around this, we have to use a type guard to narrow down the type of the object before accessing a specific property.

index.ts
async function fetchData() { try { await Promise.resolve(42); } catch (err) { if (err instanceof Error) { // ✅ TypeScript knows err is Error console.log(err.message); } else { console.log('Unexpected error', err); } } }

We used the instanceof operator to check if err is an instance of the Error object.

If it is, we can safely access the message property, because all Error instances have a message of type string.

If you are getting this error in another place, you might not be providing a type for a generic, e.g. passing a type for the return value of an HTTP request.

With the unknown type, we have to first check the type that's currently stored in the variable before we get TypeScript support.

The type is used when there's no way to know what the value stores in advance, so you can only access properties and methods on it by using type guards.

index.ts
const something: unknown = 42; if (typeof something === 'string') { console.log(something.toUpperCase()); } else if (typeof something === 'number') { console.log(something.toFixed(2)); }

For example you could check for the value's type to be able to use built-in methods.

index.ts
async function fetchData() { try { await Promise.resolve(42) } catch (err) { // 👈️ err is unknown if (typeof err === 'object' && err !== null) { console.log(err.toString()); } else { console.log('Unexpected error', err); } } }

We check if err has a type of object and is not null.

The null check seems kind of random, but we have to do it, because null has a type of object in JavaScript (and TypeScript).

index.ts
console.log(typeof null); // 👉️ "object"

If err stores an object and is not null, we can use object-specific built-in methods on it - e.g. toString().

TypeScript didn't always type the error in the catch block as unknown. If you don't like this behavior, you can set the useUnknownInCatchVariables property to false in your tsconfig.json file to have the error typed as any.

tsconfig.json
{ "compilerOptions": { // ... other stuff "useUnknownInCatchVariables": false } }

If you set useUnknownInCatchVariables to false in your tsconfig.json file, the error variable will be typed as any.

index.ts
async function fetchData() { try { throw new Error('Something went wrong'); } catch (err) { // 👈️ any console.log(err.message); // ✅ OK console.log(err.anything); // ✅ OK } }

However, when using this approach you might get unexpected runtime errors, because there's no way to be certain that what's being thrown is an Error instance (especially when using 3rd party packages).

Use the search field on my Home Page to filter through my more than 1,000 articles.