nhb-toolbox
Version:
A versatile collection of smart, efficient, and reusable utility functions, classes and types for everyday development needs.
100 lines (99 loc) • 4.44 kB
TypeScript
import type { Tuple } from '../utils/types';
import type { DeepKeys, GenericObject } from './types';
/**
* * Deep clone an object using `structuredClone` or deterministic *JSON serialization*.
*
* @param obj Object to clone.
* @param serialize Whether to force deterministic JSON serialization instead of using `structuredClone`. Defaults to `false`.
* @returns Deep cloned object.
*
* @remarks
* **Primary behavior**
* - By default (`serialize = false`), the function uses {@link https://developer.mozilla.org/docs/Web/API/Window/structuredClone structuredClone} when available. This supports:
* - Circular references
* - `Date` objects
* - `Map` / `Set`
* - `RegExp`
* - Typed arrays
* - Most built-in JavaScript types
* - Preserves `undefined` values
*
* - **Note:** `structuredClone` **does not preserve class prototypes**, even though it preserves data types like `Date`, `Map`, and `Set`.
*
* **Deterministic serialization mode**
* - When `serialize = true`, or when `structuredClone` is unavailable, the function falls back to **stable JSON serialization** via `stableStringify`. This guarantees:
* - All object keys are sorted alphabetically.
* - Consistent output across environments (deterministic).
* - All `undefined` values are converted to `null`.
* - Converting date-like objects (`Date`, `Chronos`, `Moment.js`, `Day.js`, `Luxon`, `JS-Joda`, `Temporal`) **in the same way that {@link JSON.stringify} would serialize them**, ensuring predictable and JSON-compliant output.
*
* - This mode is ideal for:
* - Hashing
* - Signature generation
* - Deep equality checks
* - Anything requiring deterministic, environment-neutral output
*
* **Deterministic mode limitations**
* - JSON serialization will:
* - Drop functions and `Symbol` values.
* - Lose prototype and class instance information.
* - Convert all date-like objects into strings.
* - Fail on circular references.
*
* **Final safety fallback**
* - If JSON serialization fails (e.g., due to circular references), the function returns a **shallow clone** (`{ ...obj }`) to ensure the cloning never throws.
*/
export declare function cloneObject<T extends GenericObject>(obj: T, serialize?: boolean): T;
/**
* * Count the number of fields in an object.
*
* @param obj Object to check.
* @returns Number of fields in the object.
*/
export declare function countObjectFields<T extends GenericObject>(obj: T): number;
/**
* * Extracts all the top-level keys of an object as an array.
*
* @remarks
* - Returns a normal array of keys (string literals).
* - Safe for runtime iteration.
* - Returns an empty array (`[]`) for empty or non-object values.
*
* @param obj The object from which to extract keys.
* @returns Array of keys.
*
* @example
* const keys = extractObjectKeys({ a: 1, b: 2 });
* // keys: ["a", "b"]; typed as ("a" | "b")[]
*/
export declare function extractObjectKeys<T extends GenericObject>(obj: T): Array<keyof T>;
/**
* * Extracts all the top-level keys of an object as a tuple.
*
* @remarks
* - Returns a typed tuple based on the input type, not runtime values.
* - **Caution:** The order of keys in the returned tuple is determined by TypeScript’s type system and **may not match the runtime order** returned by `Object.keys(obj)`.
* - Use this tuple for strict type-level operations, not for runtime iteration that relies on key order.
* - Useful when you want literal type information preserved.
* - Returns an empty tuple (`[]`) for empty or non-object values.
*
* @param obj The object from which to extract keys.
* @param tuple Pass `true` to return as tuple instead of an array type.
* @returns Tuple of keys.
*
* @example
* const keysTuple = extractObjectKeys({ a: 1, b: 2 }, true);
* // keysTuple: ["a", "b"]; also typed as ["a", "b"]
*/
export declare function extractObjectKeys<T extends GenericObject>(obj: T, tuple: true): Tuple<keyof T>;
/**
* * Recursively extracts all nested keys from an object as an array.
*
* @remarks
* - Returns an empty array (`[]`) for an empty object or a non-object value.
* - For only top-level keys, use {@link extractObjectKeys}.
*
* @param obj The object from which to extract the keys.
* @returns An array of all the nested keys (string literals) from the specified object.
*/
export declare function extractObjectKeysDeep<T extends GenericObject>(obj: T): Array<DeepKeys<T>>;