跳转到内容

isEmpty 判空函数

[!TIP] 这个函数修改自 radash 项目,遵守 MIT 许可证。

export const isEmpty = (value: unknown): boolean => {
type NumericLength = { length: number };
type NumericSize = { size: number };
const hasNumericLength = (value: unknown): value is NumericLength => {
if (typeof value === "string") return true;
if (Array.isArray(value)) return true;
if (typeof value === "object" && value !== null && "length" in value) {
return typeof (value as NumericLength).length === "number";
}
return false;
};
const hasNumericSize = (value: unknown): value is NumericSize => {
return (
typeof value === "object" &&
value !== null &&
"size" in value &&
typeof (value as NumericSize).size === "number"
);
};
if (typeof value === "boolean") return true;
if (value === null || value === undefined) return true;
if (typeof value === "number") {
return Number.isFinite(value) && value === 0;
}
if (typeof value === "bigint") {
return value === 0n;
}
if (value instanceof Date) {
return Number.isNaN(value.getTime());
}
if (typeof value === "function") return false;
if (typeof value === "symbol") return false;
if (hasNumericLength(value)) {
return value.length === 0;
}
if (hasNumericSize(value)) {
return value.size === 0;
}
const keys = Object.keys(Object(value));
return keys.length === 0;
};
import { describe, expect, test } from "vitest";
import { isEmpty } from "../is-empty";
describe("isEmpty", () => {
class BareClass {}
class TestClass {
name = "isEmptyTest";
}
test("treats boolean values as empty", () => {
expect(isEmpty(true)).toBe(true);
expect(isEmpty(false)).toBe(true);
});
test("handles nullish values", () => {
expect(isEmpty(null)).toBe(true);
expect(isEmpty(undefined)).toBe(true);
});
test("handles numbers", () => {
expect(isEmpty(0)).toBe(true);
expect(isEmpty(1)).toBe(false);
expect(isEmpty(-5)).toBe(false);
expect(isEmpty(Number.POSITIVE_INFINITY)).toBe(false);
});
test("handles bigint values", () => {
expect(isEmpty(0n)).toBe(true);
expect(isEmpty(123n)).toBe(false);
});
test("handles Date objects", () => {
expect(isEmpty(new Date("invalid"))).toBe(true);
expect(isEmpty(new Date())).toBe(false);
});
test("functions and symbols are not empty", () => {
expect(isEmpty(() => null)).toBe(false);
expect(isEmpty(Symbol(""))).toBe(false);
expect(isEmpty(Symbol("id"))).toBe(false);
});
test("handles values with numeric length", () => {
expect(isEmpty("")).toBe(true);
expect(isEmpty("text")).toBe(false);
expect(isEmpty([])).toBe(true);
expect(isEmpty([1])).toBe(false);
expect(isEmpty({ length: 0 })).toBe(true);
expect(isEmpty({ length: 2 })).toBe(false);
});
test("handles values with numeric size", () => {
expect(isEmpty(new Map())).toBe(true);
expect(isEmpty(new Map([["key", "value"]]))).toBe(false);
expect(isEmpty(new Set())).toBe(true);
expect(isEmpty(new Set([1]))).toBe(false);
});
test("handles plain and object values", () => {
expect(isEmpty({})).toBe(true);
expect(isEmpty({ a: 1 })).toBe(false);
const child = Object.create({ a: 1 });
expect(isEmpty(child)).toBe(true);
expect(isEmpty(new BareClass())).toBe(true);
expect(isEmpty(new TestClass())).toBe(false);
});
});