Last updated: Feb 27, 2024
Reading time·7 min
Object
type when typing objectsThe "Property does not exist on type '{}'" error occurs when we try to access or set a property that is not contained in the object's type.
To solve the error, type the object properties explicitly or use a type with variable key names.
Here is an example of how the error occurs:
const obj = {}; // ⛔️ Error: Property 'name' does not exist on type '{}'.ts(2339) obj.name = 'Bobby Hadz';
You might also get the error if you use the Object
type.
const obj: Object = {}; // ⛔️ Property 'name' does not exist on type 'Object'. obj.name = 'Bobby Hadz';
We didn't explicitly type the obj
variable and initialized it to an empty
object, so we aren't able to assign or access properties that don't exist on the
object's type.
To solve the error, type the object explicitly and specify all of the properties you intend to access.
// ✅ When you know property names ahead of time type Employee = { id?: number; name?: string; }; const obj: Employee = {}; obj.id = 1; obj.name = 'Bobby Hadz';
If you don't know all of the property names ahead of time, use an index signature.
// ✅ When you don't know ALL property names ahead of time type Employee = { [key: string]: any; // 👈️ variable key name: string; }; const obj: Employee = { name: 'Bobby Hadz', }; obj.salary = 100;
The first example shows how to type an object when you know its property names and the type of its values ahead of time.
We need to declare the object as empty, so we marked the properties as optional by using a question mark.
// ✅ When you know property names ahead of time type Employee = { id?: number; name?: string; }; const obj: Employee = {}; obj.id = 1; obj.name = 'Bobby Hadz';
id
and name
properties can be assigned later on.The properties exist on the object's type, so we won't get the "Property does not exist on type 'Object'" error when accessing them.
You can also
make all of an object's properties optional
by using the Partial
type.
In some cases, you won't know the names of all of the object's keys or the shape of the values ahead of time.
type Employee = { [key: string]: any; // 👈️ variable key name: string; }; const obj: Employee = { name: 'Bobby Hadz', }; obj.salary = 100;
The {[key: string]: any} syntax is called an index signature and is used when you don't know the names of the object's keys or the shape of the values ahead of time.
The syntax means that when the object is indexed with a string key, it will
return a value of any
type.
We set the name
property to string
in the Employee
type, so the type
checker would throw an error if the property is not provided or is set to a
value of a different type.
If you don't know the names of all of the object's keys but know the shape of the values, you can use a more specific index signature for better type safety.
type Employee = { [key: string]: string | number; name: string; id: number; }; const obj: Employee = { id: 1, name: 'Bobby Hadz', }; obj.department = 'accounting'; obj.salary = 100;
The index signature means that when the object is indexed with a string key, it
will return a value that has a string
or number
type.
The string | number
syntax is called a
union type in TypeScript.
name
and id
properties are strings and they return different types.In other words, you can't specify that when the object is indexed with a string
key, it returns a value of type string
and then add another string key to the
interface that has a value of
type number
.
type Employee = { [key: string]: string; name: string; // ⛔️ Error: Property 'id' of type 'number' is // not assignable to 'string' index type 'string'.ts(2411) id: number; };
The example shows that the type checker throws an error if we specify that when
indexed with a string key, the object returns a value of type string
and try
to add another string key that has a value of type number
.
any
type if you want to turn off type-checkingIf you just want to turn off type checking and be able to add any property to
the object, set its type to any
.
const obj: any = {}; obj.name = 'Bobby Hadz'; obj.age = 30; console.log(obj); // 👉️ { name: 'Bobby Hadz', age: 30 }
The any
type effectively
turns off type checking and enables us
to add any property to the object.
However, when we use this approach we don't take advantage of the benefits that TypeScript provides.
Object
type when typing objectsThe following code sample raises the same error when we try to access a property that doesn't exist on the object's type.
const obj: Object = { name: 'Bobby Hadz', age: 30, }; // ⛔️ Error: Property 'country' does not exist on type 'Object'.ts(2339) obj.country = 'Chile';
We typed the obj
variable as Object
and tried to access the country
property on the object.
country
property does not exist on the Object
type, so the type checker throws an error.This is only 1 of the issues in the code sample.
The Object
type should never be used to type a value in TypeScript.
The Object
type means "any non-nullish value". In other words, it means any
value that is not null
or undefined
.
The "property does not exist on type union" error occurs when we try to access a property that is not present on every object in the union type.
To solve the error, use a type guard to ensure the property exists on the object before accessing it.
Here is an example of how the error occurs.
type Person = { age: number; }; type Employee = { salary: number; }; function getProperty(obj: Person | Employee): number { // ⛔️ Error: Property 'age' does not exist on type 'Person | Employee'. if (obj.age) { return obj.age; } return obj.salary; }
The age
property doesn't exist on all of the types in the
union,
so we aren't able to access it directly.
Instead, we have to use a type guard to check if the property exists in the object before accessing it.
type Person = { age: number; }; type Employee = { salary: number; }; function getProperty(obj: Person | Employee): number { if ('age' in obj) { return obj.age; } return obj.salary; }
We used the in operator, which is a type guard in TypeScript.
The in
operator returns true
if the specified property is in the object or
its prototype chain.
const obj = { a: 'hello', }; console.log('a' in obj); // 👉️ true console.log('b' in obj); // 👉️ false
This way, TypeScript can infer the type of the object in the if
block and
after the if
block.
type Person = { age: number; }; type Employee = { salary: number; }; function getProperty(obj: Person | Employee): number { if ('age' in obj) { // 👇️ now `obj` is type `Person` return obj.age; } // 👇️ now `obj` is type `Employee` return obj.salary; }
age
property is contained in the passed-in object, we can safely use the age
property and TypeScript is able to infer the type of obj
to be Person
.If the if
block doesn't run, then the age
property isn't in the passed-in
object and TypeScript infers the type of obj
to be Employee
.
If you need to check if a string is in a union type, click on the following article.
The error "Property 'status' does not exist on type 'Error'" occurs because
the status
property is not available on the Error
interface.
To solve the error, add the specific property to the Error
interface or
create a custom class that extends from Error
.
Here is an example of how the error occurs.
const err = new Error('Something went wrong'); // ⛔️ Property 'status' does not exist on type 'Error'.ts(2339) err.status = 500; // ⛔️ Property 'code' does not exist on type 'Error'.ts(2339) console.log(err.code);
The reason we got the errors in the example above is that the status
and
code
properties don't exist on the Error
interface.
By default, the Error
interface has the following properties:
interface Error { name: string; message: string; stack?: string; }
To get around this, we can extend the Error
class.
export class CustomError extends Error { status: number = 200; code: number = 200; constructor(message: string) { super(message); // 👇️ because we are extending a built-in class Object.setPrototypeOf(this, CustomError.prototype); } } const err = new CustomError('Something went wrong'); err.status = 500; console.log(err.status); err.code = 500; console.log(err.code);
The CustomError
class extends from the built-in Error
class and adds the
status
and code
properties.
If you want to read more on how to extend from the Error
class in TypeScript,
check out this article.
You can learn more about the related topics by checking out the following tutorials: