Skip to content

Commit e630309

Browse files
committed
feat: ✨ Add isEmpty helper
1 parent 89ee0ef commit e630309

2 files changed

Lines changed: 116 additions & 0 deletions

File tree

helpers/type/isEmpty.test.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
* This file is part of helpers4.
3+
* Copyright (C) 2025 baxyz
4+
* SPDX-License-Identifier: AGPL-3.0-or-later
5+
*/
6+
7+
import { describe, expect, it } from 'vitest';
8+
import { isEmpty } from './isEmpty';
9+
10+
describe('isEmpty', () => {
11+
it('should treat null and undefined as empty', () => {
12+
expect(isEmpty(null)).toBe(true);
13+
expect(isEmpty(undefined)).toBe(true);
14+
});
15+
16+
it('should handle strings', () => {
17+
expect(isEmpty('')).toBe(true);
18+
expect(isEmpty(' ')).toBe(false);
19+
expect(isEmpty('text')).toBe(false);
20+
});
21+
22+
it('should handle arrays', () => {
23+
expect(isEmpty([])).toBe(true);
24+
expect(isEmpty([1])).toBe(false);
25+
});
26+
27+
it('should handle plain objects', () => {
28+
expect(isEmpty({})).toBe(true);
29+
expect(isEmpty({ a: 1 })).toBe(false);
30+
});
31+
32+
it('should handle objects with null prototype', () => {
33+
const obj = Object.create(null) as Record<string, unknown>;
34+
expect(isEmpty(obj)).toBe(true);
35+
obj.key = 'value';
36+
expect(isEmpty(obj)).toBe(false);
37+
});
38+
39+
it('should handle Map and Set', () => {
40+
expect(isEmpty(new Map())).toBe(true);
41+
expect(isEmpty(new Set())).toBe(true);
42+
expect(isEmpty(new Map([['key', 'value']]))).toBe(false);
43+
expect(isEmpty(new Set([1]))).toBe(false);
44+
});
45+
46+
it('should return false for special objects', () => {
47+
expect(isEmpty(new Date())).toBe(false);
48+
class Example {}
49+
expect(isEmpty(new Example())).toBe(false);
50+
});
51+
52+
it('should return false for numbers, booleans and functions', () => {
53+
expect(isEmpty(0)).toBe(false);
54+
expect(isEmpty(false)).toBe(false);
55+
expect(isEmpty(() => undefined)).toBe(false);
56+
});
57+
});

helpers/type/isEmpty.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/**
2+
* This file is part of helpers4.
3+
* Copyright (C) 2025 baxyz
4+
* SPDX-License-Identifier: AGPL-3.0-or-later
5+
*/
6+
7+
import { isSpecialObject } from './isSpecialObject';
8+
9+
/**
10+
* Checks if a value is empty.
11+
*
12+
* Supported types:
13+
* - `null` / `undefined` → empty
14+
* - `string` → length === 0
15+
* - `array` → length === 0
16+
* - `Map` / `Set` → size === 0
17+
* - plain object → no own enumerable properties
18+
*
19+
* @param value - The value to check
20+
* @returns `true` if the value is considered empty, `false` otherwise
21+
*
22+
* @example
23+
* isEmpty('') // true
24+
* isEmpty([]) // true
25+
* isEmpty({}) // true
26+
* isEmpty('foo') // false
27+
*/
28+
export function isEmpty(value: unknown): boolean {
29+
if (value === null || value === undefined) {
30+
return true;
31+
}
32+
33+
if (typeof value === 'string') {
34+
return value.length === 0;
35+
}
36+
37+
if (Array.isArray(value)) {
38+
return value.length === 0;
39+
}
40+
41+
if (value instanceof Map || value instanceof Set) {
42+
return value.size === 0;
43+
}
44+
45+
if (typeof value === 'object') {
46+
if (isSpecialObject(value)) {
47+
return false;
48+
}
49+
50+
const proto = Object.getPrototypeOf(value);
51+
if (proto !== Object.prototype && proto !== null) {
52+
return false;
53+
}
54+
55+
return Object.keys(value as Record<string, unknown>).length === 0;
56+
}
57+
58+
return false;
59+
}

0 commit comments

Comments
 (0)