How to Check if an Object Is Empty in TypeScript

To check if an object is empty in TypeScript, count its own keys: Object.keys(obj).length === 0 is true for {} and false as soon as the object has a property. In real code you also need to handle null and undefined, and decide what to do with arrays, dates and class instances. This guide builds a type-safe isEmptyObject check, compares Object.keys, JSON.stringify, for...in and Reflect.ownKeys, and explains the TypeScript empty object type (why {} is not what you think).

Every example was compiled with TypeScript 5.2.2 and Node.js v22.22.2 in the Windows Command Prompt, using tsc --target es2022 --lib es2023,dom --strict file.ts and node file.js. Reference: Object.keys() on MDN and Record<Keys, Type> in the TypeScript Handbook.

Check if an object is empty with Object.keys()

const settings: Record<string, unknown> = {};
const user = { name: "Ava", city: "Chicago" };

console.log(Object.keys(settings).length === 0);   // true  -> empty
console.log(Object.keys(user).length === 0);       // false -> has properties

settings.theme = "dark";
console.log(Object.keys(settings).length === 0);   // false now

Output:

true
false
false
Command Prompt showing a TypeScript file compiled with tsc and run with node that checks if an object is empty with Object.keys length
Object.keys(obj).length === 0 before and after adding a property.

Object.keys() returns the object’s own enumerable string keys. A property whose value is undefined still counts as a key, so { a: undefined } is not empty.

A reusable, type-safe isEmptyObject function

This helper accepts any value, so you can call it on API data of unknown shape. It returns false for null, undefined, arrays, dates and maps, and its return type value is Record<string, never> is a type guard that narrows the value when the result is true:

function isEmptyObject(value: unknown): value is Record<string, never> {
  return (
    typeof value === "object" &&
    value !== null &&
    Object.getPrototypeOf(value) === Object.prototype &&   // only plain {} objects
    Object.keys(value).length === 0
  );
}

const samples: [string, unknown][] = [
  ["{}", {}],
  ["{ a: 1 }", { a: 1 }],
  ["{ a: undefined }", { a: undefined }],
  ["null", null],
  ["undefined", undefined],
  ["[]", []],
  ["new Date()", new Date()],
  ["new Map()", new Map()],
  ["Object.create(null)", Object.create(null)],
];

for (const [label, value] of samples) {
  console.log(label.padEnd(20), isEmptyObject(value));
}

Output:

{}                   true
{ a: 1 }             false
{ a: undefined }     false
null                 false
undefined            false
[]                   false
new Date()           false
new Map()            false
Object.create(null)  false
Command Prompt output of a TypeScript isEmptyObject type guard returning true for {} and false for objects with keys, null, undefined, arrays, Date and Map
Only plain objects without keys count as empty.

Object.create(null) has no prototype, so the prototype check rejects it. If you work with such dictionaries, change that line to also accept null as the prototype. new Date() and new Map() would pass a plain Object.keys test (they have no own keys), which is why the helper checks the prototype. For a Map or Set, use .size === 0 instead.

Handle null and undefined

Object.keys(null) throws a TypeError. If a value can be missing, fall back to an empty object with ??:

function hasNoKeys(obj: object | null | undefined): boolean {
  return Object.keys(obj ?? {}).length === 0;      // ?? {} treats null/undefined as empty
}

const apiResponse = JSON.parse("null") as Record<string, unknown> | null;
console.log(hasNoKeys(apiResponse));
console.log(hasNoKeys({ id: 7 }));

try {
  Object.keys(apiResponse as object);              // what happens without the check
} catch (e) {
  console.log(String(e));
}

Output:

true
false
TypeError: Cannot convert undefined or null to object

Object.keys vs JSON.stringify vs for…in

Every common empty-object check gives the same answer for normal data objects, but they disagree on the edge cases:

const sym = Symbol("id");
const cases: Record<string, object> = {
  "plain {}": {},
  "symbol key": { [sym]: 1 },
  "non-enumerable": Object.defineProperty({}, "hidden", { value: 1, enumerable: false }),
  "inherited only": Object.create({ inherited: 1 }),
  "new Date()": new Date(),
};

const isEmpty = {
  keys: (o: object) => Object.keys(o).length === 0,
  json: (o: object) => JSON.stringify(o) === "{}",
  forIn: (o: object) => { for (const _ in o) return false; return true; },
  ownKeys: (o: object) => Reflect.ownKeys(o).length === 0,
};

console.log("case".padEnd(16), Object.keys(isEmpty).map(k => k.padEnd(8)).join(""));
for (const [label, obj] of Object.entries(cases)) {
  console.log(label.padEnd(16), Object.values(isEmpty).map(f => String(f(obj)).padEnd(8)).join(""));
}

Output:

case             keys    json    forIn   ownKeys 
plain {}         true    true    true    true    
symbol key       true    true    true    false   
non-enumerable   true    true    true    false   
inherited only   true    true    false   true    
new Date()       true    false   true    true
Command Prompt table comparing Object.keys, JSON.stringify, for...in and Reflect.ownKeys empty checks on symbol keys, non-enumerable, inherited properties and Date
The four checks on five edge cases.
CheckWhat it countsNotes
Object.keys(o).length === 0Own enumerable string keysFast and clear; the usual choice
JSON.stringify(o) === "{}"What JSON would includeSlow on large objects; a Date becomes a string, so it is not “{}”
for...in loopOwn and inherited enumerable keysStops at the first key, no array created
Reflect.ownKeys(o).length === 0All own keys, including symbols and non-enumerableThe strictest check

Lodash’s _.isEmpty() works too, but it also returns true for numbers, booleans and empty strings, so it is less precise than a dedicated object check.

The TypeScript empty object type

A common mistake is typing a value as {} to mean “an empty object”. In TypeScript, {} means any value that is not null or undefined, so even a number is allowed:

let anything: {} = 42;             // compiles: {} means "any value except null and undefined"
anything = "text";
console.log(typeof anything);

type EmptyObject = Record<string, never>;
const empty: EmptyObject = {};     // only an object with no properties
console.log(Object.keys(empty).length);

Output:

string
0

To type an object that must have no properties, use Record<string, never>. Adding a property is then a compile-time error:

type EmptyObject = Record<string, never>;

const ok: EmptyObject = {};
const notEmpty: EmptyObject = { page: 1 };

tsc output:

empty_type_error.ts(4,33): error TS2322: Type 'number' is not assignable to type 'never'.
Command Prompt showing tsc error TS2322 Type number is not assignable to type never for an object typed as Record string never
Record<string, never> rejects any property.

For “any object” (not a primitive), use object or Record<string, unknown>.

Treat objects with only empty values as empty

Form filters and query parameters often have keys whose values are blank. Remove those first, then check the keys:

interface Filters {
  city?: string;
  minPrice?: number;
  tags?: string[];
}

const filters: Filters = { city: "", minPrice: undefined, tags: [] };

const active = Object.fromEntries(
  Object.entries(filters).filter(([, v]) => v !== undefined && v !== "" && !(Array.isArray(v) && v.length === 0))
) as Partial<Filters>;

console.log(active, Object.keys(active).length === 0 ? "-> no filters set" : "-> filters set");

Output:

{} -> no filters set

More TypeScript tutorials you may find useful:

Frequently asked questions

How do I check if an object is empty in TypeScript?

Use Object.keys(obj).length === 0. Add obj != null first if the object can be null or undefined.

What is the TypeScript type for an empty object?

Record<string, never>. The type {} means any non-null value, not an empty object.

Is { a: undefined } an empty object?

No. It has the key a, so Object.keys() returns ["a"]. Remove undefined values first if they should not count.

Why does Object.keys(new Date()) return an empty array?

A Date has no own enumerable properties. Check that the prototype is Object.prototype if only plain objects should count as empty.

Can I use JSON.stringify(obj) === “{}”?

It works for plain data objects, but it is slower and gives surprising results for dates, symbols and undefined values.

How do I check if a Map or Set is empty?

Use the size property: map.size === 0.