Last updated: Feb 27, 2024
Reading timeยท3 min
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) {}
.
Here is an example of how the error occurs.
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.
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 its message
property because all Error
instances have a message
of type string
.
If you need to create a custom class that extends from Error
, check out the
following article.
If you got the error in a different place, you might not be providing a type for a generic.
For example, you might not be passing a type for the return value of an HTTP request.
unknown
type, we first have to 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 variable stores in advance.
Before accessing a specific property or a method, we have to use a type guard.
const something: unknown = 42; if (typeof something === 'string') { console.log(something.toUpperCase()); } else if (typeof something === 'number') { // ๐๏ธ this runs console.log(something.toFixed(2)); }
For example, you could check for the value's type to be able to use built-in methods.
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 is necessary because null
has
a type of object
in JavaScript (and TypeScript).
console.log(typeof null); // ๐๏ธ "object"
err
stores an object and is not null
, we can safely use object-specific built-in methods, e.g. toString()
.I've written a detailed guide on how to check if a value with an unknown type contains a property.
tsconfig.json
file to solve the errorTypeScript 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
.
{ "compilerOptions": { // ... other stuff "useUnknownInCatchVariables": false } }
If you set useUnknownInCatchVariables
to false
in your tsconfig.json
file,
the error variable will be typed as any
.
async function fetchData() { try { throw new Error('Something went wrong'); } catch (err) { // ๐๏ธ err is type 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 third-party packages).
You can learn more about the related topics by checking out the following tutorials: