Last updated: Feb 27, 2024
Reading time·4 min
To check if a property exists in an object in TypeScript:
undefined
, it exists in the object.type Employee = { name?: string; department?: string; country?: string; }; const emp: Employee = {}; // ✅ Explicitly checking if (emp.department !== undefined) { console.log(emp.department.toLowerCase()); // now string } // ✅ Using optional chaining console.log(emp.department?.toLowerCase());
Note that we used a question mark to set the properties in the Employee
type
to
optional.
undefined
, or a value of type string
.If you don't have all of the property names in the object in advance, use an index signature.
type Employee = { [key: string]: string; }; const emp: Employee = {}; // ✅ Explicitly checking if (emp.department !== undefined) { console.log(emp.department.toLowerCase()); // now string } // ✅ Using optional chaining console.log(emp.department?.toLowerCase());
The {[key: string]: string}
syntax is an index signature and is used when we
don't know all of the object's properties ahead of time, but know the shape of
the values.
In either scenario, you can only check if a property exists in a TypeScript object if the property is compatible with the object's type.
type Employee = { name?: string; department?: string; country?: string; }; const emp: Employee = {}; // ⛔️ Property 'randomkey' does not exist on type 'Employee'. if (emp.randomkey !== undefined) { }
The Employee
type doesn't have a randomkey
property, so we aren't able to
check if it exists in the object.
undefined
The best way to check for a key's existence in TypeScript is to explicitly check
if accessing the specific key in the object returns a value of undefined
.
type Employee = { name?: string; department?: string; country?: string; }; const emp: Employee = {}; // 👇️ (property) department?: string | undefined emp.department // ✅ Explicitly checking if (emp.department !== undefined) { console.log(emp.department.toLowerCase()); }
The department
property has a type of string
or undefined
because it's
marked as optional.
However, in the if
statement, its type is string
. This is called a
type guard in TypeScript.
We can use any string-specific built-in methods in the if
statement because
TypeScript knows that if the department
property isn't undefined
, then it is
a string
.
if
statement wouldn't run if the property is explicitly set to undefined
in the object.Alternatively, you can use optional chaining (?.).
You can also use the optional chaining (?.) operator to check if a property exists in an object.
type Employee = { address?: { country?: string; city?: string; }; }; const emp: Employee = {}; // ✅ Using optional chaining console.log(emp.address?.country?.toLowerCase()); console.log(emp.address?.city?.toLowerCase()); if (emp.address?.country !== undefined) { // ✅ Now emp.address.country is string console.log(emp.address.country.toLowerCase()); }
If the property exists in the object, the optional chaining (?.) operator will
return the corresponding value, otherwise, the operator short-circuits returning
undefined
.
You can also use this approach to check for the existence of deeply nested properties in an object.
I've also written an article on how to get an object's key by value in TS.
in
and hasOwnProperty
You might see examples online that use the in
operator or the hasOwnProperty
method to check for a key's existence in an object.
type Employee = { name?: string; department?: string; country?: string; }; const emp: Employee = {}; if ('department' in emp) { // 👇️ (property) department?: string | undefined console.log(emp.department); } if (emp.hasOwnProperty('department')) { // 👇️ (property) department?: string | undefined console.log(emp.department); }
The
in operator
returns true
if the specified key is in the object or its prototype chain.
However, note that the type of the department
property in the if
block is
still string | undefined
.
department
key in the object to have a value of undefined
.This would work in a different way if you use an index signature like
{[key: string]: string}
.
type Employee = { [key: string]: string; }; const emp: Employee = {}; if ('department' in emp) { // 👇️ emp.department is string console.log(emp.department); } if (emp.hasOwnProperty('department')) { // 👇️ emp.department is string console.log(emp.department); }
The index signature {[key: string]: string}
means that when the object is
indexed with a string key, it will always return a value of type string
.
This is why the in
operator and the hasOwnProperty
method are able to serve
as type guards and determine the type of the department
property to be a
string in the if
statements.
The
hasOwnProperty
method is different from the in
operator because it checks if the property
exists directly on the object (excluding its prototype chain).
type Employee = { [key: string]: string; }; const emp: Employee = {}; if (emp.hasOwnProperty('department')) { // 👇️ emp.department is string console.log(emp.department); }
If ESLint is giving you an error, you can get around it by calling the method on
the Object.prototype
.
type Employee = { [key: string]: string; }; const emp: Employee = {}; if (Object.prototype.hasOwnProperty.call(emp, 'department')) { // 👇️ emp.department is string console.log(emp.department); }
Which approach you pick is a matter of personal preference. I'd go with
explicitly checking if accessing the property in the object returns a value of
undefined
as it is the easiest to read and the most explicit approach.