UNPKG

@rzl-zone/utils-js

Version:

A modern, lightweight set of JavaScript utility functions with TypeScript support for everyday development, crafted to enhance code readability and maintainability.

997 lines (977 loc) 98.5 kB
/*! * ==================================================== * Rzl Utils-JS. * ---------------------------------------------------- * Version: 3.11.0. * Author: Rizalvin Dwiky. * Repository: https://github.com/rzl-zone/utils-js. * ==================================================== */ import { Nullish, KeepNull, KeepUndef, AnyFunction, NormalizeEmptyArraysRecursive, RemoveEmptyArrayElements, FixNeverArrayRecursive, IfNotExtends, IfExtends, IsAny, NumberRangeUnion, Prettify, OrArr, Extends, AndArr, TypedArray, WebApiObjects, IntlObjects } from '@rzl-zone/ts-types-plus'; type NormalizeInputToNumberArrayUnRecursive<T> = T extends string | bigint | boolean | number | Nullish ? T : HasNonNumberLikeNonNullish<T>; /** Detects whether `T` contains any number-like type (`string | number | bigint`). * * @template T Input type. * @returns `true` if `T` contains number-like, otherwise `false`. */ type HasNumberLike<T> = [Extract<T, string | bigint | number>] extends [never] ? false : true; /** Detects whether `T` contains a string type. * * - Useful for identifying values that may fail parsing to number (`undefined` when `R=false`). * * @template T Input type. * @returns `true` if `T` contains `string`, otherwise `false`. */ type HasString<T> = [Extract<T, string>] extends [never] ? false : true; /** Detects whether `T` contains non-number-like, non-nullish values (`objects`, `arrays`, `symbols`, `functions`, `etc`.). * * @template T Input type. * @returns `true` if such types exist, otherwise `false`. */ type HasNonNumberLikeNonNullish<T> = [ Exclude<T, string | bigint | number | Nullish> ] extends [never] ? false : true; /** ------------------------------------------------------- * * ***Computes the return type of {@link toNumberArrayUnRecursive|`toNumberArrayUnRecursive`} * based on input type `T` and option `R`.*** * ------------------------------------------------------- * * **Behavior:** * - If `R = true` (`removeInvalidValueNumber: true`): * - If `T` is only `null | undefined` ➔ returns `[]`. * - If `T` contains number-like (`string | number | bigint`) ➔ returns `number[]`. * - Otherwise ➔ returns `[]`. * - If `R = false` (`removeInvalidValueNumber: false`): * - Preserves `null[]` or `undefined[]` if input is purely nullish. * - Otherwise returns an array of: * - `number` if `T` includes number-like. * - `undefined` if parsing fails (string or invalid non-number-like). * - Original `null` / `undefined` from input. * @template T Input element type. * @template R Flag indicating whether invalid values should be removed (`true`) or kept (`false`). * */ type ToNumberArrayUnRecursiveReturn<T, R extends boolean> = R extends true ? [ Exclude<T, null | undefined> ] extends [never] ? [] : HasNumberLike<T> extends true ? number[] : [] : [ Exclude<T, null> ] extends [never] ? null[] : [Exclude<T, undefined>] extends [never] ? undefined[] : Array<(HasNumberLike<T> extends true ? number : never) | (HasString<T> extends true ? undefined : never) | (HasNonNumberLikeNonNullish<T> extends true ? undefined : never) | KeepNull<T> | KeepUndef<T>>; /** ------------------------------------------------------- * * ***Options for {@link toNumberArrayUnRecursive|`toNumberArrayUnRecursive`}.*** * ------------------------------------------------------- * * @template T Flag indicating whether invalid values should be removed. */ type ToNumberArrayUnRecursiveOptions<T extends boolean> = { /** If true, removes invalid number values (`NaN`, non-numeric strings, `null`, `undefined`) from the result, defaultValue: `true`. * * @default true */ removeInvalidValueNumber?: T; }; /** ------------------------------------------------------- * * ***Utility: `toNumberArrayUnRecursive`.*** * ------------------------------------------------------- * **Converts a flat array of strings, numbers, nulls, or undefineds into numbers.** * - **Behavior:** * - Only supports **flat arrays** (non-recursive). * - Valid inputs: `string`, `number`, `null`, `undefined`. * - `BigInt` will be converted to `number`. * - Other values ➔ coerced into `undefined`. * - Invalid values can be **removed** (`removeInvalidValueNumber: true`) or **kept** (`false`). * - **ℹ️ Note:** * - _For recursive / nested arrays, use ***`toNumberDeep` utility function*** instead._ * @template T - Element type of the input array. * @template R - Whether invalid values should be removed (`true`) or kept (`false`). * @param {Array<T> | readonly T[] | null | undefined} [array] - The array to convert, returns `undefined` if not an array. * @param {ToNumberArrayUnRecursiveOptions<RemoveInvalidValue>} [options] - Options to control transformation behavior, defaults to `{ removeInvalidValueNumber: true }`. * @returns {ToNumberArrayUnRecursiveReturn<NormalizeInput<T>, RemoveInvalidValue>} A new array of string representations, with invalid values optionally removed. * @example * ```ts * toNumberArrayUnRecursive(['1', 2, '3']); * // ➔ [1, 2, 3] * toNumberArrayUnRecursive([1, null, undefined, 'abc']); * // ➔ [1] * toNumberArrayUnRecursive(['1', null, undefined, 'abc'], { * removeInvalidValueNumber: false * }); * // ➔ [1, null, undefined, undefined] * toNumberArrayUnRecursive(null); // ➔ undefined * toNumberArrayUnRecursive(undefined); // ➔ undefined * toNumberArrayUnRecursive(1); // ➔ undefined * ``` */ declare function toNumberArrayUnRecursive(array?: null | undefined, options?: ToNumberArrayUnRecursiveOptions<boolean>): undefined; declare function toNumberArrayUnRecursive(array?: Array<never>, options?: ToNumberArrayUnRecursiveOptions<boolean>): []; declare function toNumberArrayUnRecursive<T, R extends boolean = true>(array?: Array<T> | readonly T[] | null, options?: ToNumberArrayUnRecursiveOptions<R>): ToNumberArrayUnRecursiveReturn<NormalizeInputToNumberArrayUnRecursive<T>, R>; declare function toNumberArrayUnRecursive<T = unknown>(array?: T, options?: ToNumberArrayUnRecursiveOptions<boolean>): undefined; /** Union of primitive types that can be safely converted to string. */ type AllowedToString = string | number | boolean | bigint; /** Checks whether `T` contains any type that is allowed for conversion to string. * * - Returns `true` if `T` contains `string`, `number`, `boolean`, or `bigint`. * - Otherwise returns `false`. * * @template T Input type to check. */ type HasAllowed<T> = [Extract<T, AllowedToString>] extends [never] ? false : true; /** Checks whether `T` contains any non-nullish value that is disallowed for conversion. * * - Disallowed non-nullish types include `objects`, `arrays`, `symbols`, `functions`, `etc`. * - Returns `true` if such types exist, otherwise `false`. * @template T Input type to check. */ type HasDisallowedNonNullish<T> = [Exclude<T, AllowedToString | Nullish>] extends [never] ? false : true; /** ------------------------------------------------------- * * ***Computes the return type of {@link toStringArrayUnRecursive|`toStringArrayUnRecursive`} * based on input type `T` and option `R`.*** * ------------------------------------------------------- * * **Behavior:** * - If `R = true` (`removeInvalidValue = true`): * - If `T` contains any allowed values ➔ `string[]`. * - If `T` contains only nullish or disallowed types ➔ `[]`. * * - If `R = false` (`removeInvalidValue = false`): * - Include `string` if `T` has allowed values. * - Include `undefined` if `T` has disallowed non-nullish values. * - Preserve `null` and `undefined` from original `T`. * @template T Input element type. * @template R Flag indicating whether invalid values should be removed (`true`) or kept (`false`). */ type ToStringArrayUnRecursiveReturn<T, R extends boolean> = R extends true ? HasAllowed<T> extends true ? string[] : [] : Array<(HasAllowed<T> extends true ? string : never) | (HasDisallowedNonNullish<T> extends true ? undefined : never) | KeepNull<T> | KeepUndef<T>>; /** ------------------------------------------------------- * * ***Options for {@link toStringArrayUnRecursive|`toStringArrayUnRecursive`}.*** * ------------------------------------------------------- * * @template T Flag indicating whether invalid values should be removed. */ type ToStringArrayUnRecursiveOptions<T extends boolean> = { /** If true, removes invalid values (`null` and `undefined`) from the output, defaultValue: `true`. * * @default true */ removeInvalidValue?: T; }; /** --------------------------------------------- * * ***Utility: `toStringArrayUnRecursive`.*** * --------------------------------------------- * **Converts all values in a flat array into string representations.** * - **Behavior:** * - Only processes **flat arrays** (non-recursive). * - Supports input values: `string`, `number`, `bigint`, `boolean`, * `null`, `undefined`. * - Invalid values (`null` and `undefined`) can be **removed** or **kept** * depending on the option. * - Other unsupported types will be converted to `undefined` (and removed * if `removeInvalidValue=true`). * - **ℹ️ Note:** * - _For recursive / nested arrays, use ***`toStringDeep` utility function*** instead._ * @template T - Element type of the input array. * @template R - Whether invalid values should be removed (`true`) or kept (`false`). * @param {Array<string | number | bigint | boolean | null | undefined> | null | undefined} [array] - The array to convert, returns `undefined` if not an array. * @param {ToStringArrayUnRecursiveOptions<RemoveInvalidValue>} [options] - Options to control transformation behavior, defaults to `{ removeInvalidValue: true }`. * @param {RemoveInvalidValue extends true ? boolean : boolean} [options.removeInvalidValue=true] Whether to remove invalid values (`null`, `undefined`, or unsupported types), default: `true`. * @returns {RemoveInvalidValue extends true ? string[] : (string | null | undefined)[]} A new array of string representations, with invalid values optionally removed. * @example * ```ts * // Convert numbers and strings * toStringArrayUnRecursive([1, 2, '3']); * // ➔ ['1', '2', '3'] * // Remove null and undefined * toStringArrayUnRecursive([1, null, undefined, 'abc'], { * removeInvalidValue: true * }); * // ➔ ['1', 'abc'] * // Keep null and undefined * toStringArrayUnRecursive([1, null, undefined, 'abc'], { * removeInvalidValue: false * }); * // ➔ ['1', null, undefined, 'abc'] * // Convert boolean and bigint * toStringArrayUnRecursive([true, false, 10n]); * // ➔ ['true', 'false', '10'] * // Not an array ➔ returns undefined * toStringArrayUnRecursive(null); * // ➔ undefined * toStringArrayUnRecursive(undefined); * // ➔ undefined * toStringArrayUnRecursive(1); * // ➔ undefined * toStringArrayUnRecursive("string"); * // ➔ undefined * ``` */ declare function toStringArrayUnRecursive(array?: undefined | null, options?: ToStringArrayUnRecursiveOptions<boolean>): undefined; declare function toStringArrayUnRecursive(array?: Array<never>, options?: ToStringArrayUnRecursiveOptions<boolean>): []; declare function toStringArrayUnRecursive<T, R extends boolean = true>(array?: Array<T> | readonly T[] | null, options?: ToStringArrayUnRecursiveOptions<R>): ToStringArrayUnRecursiveReturn<T, R>; declare function toStringArrayUnRecursive<T = unknown>(array?: T, options?: ToStringArrayUnRecursiveOptions<boolean>): undefined; type ResUnFTN<Force extends false | "stringOrNumber" | "primitives" | "all" = false> = Force extends "all" ? Array<unknown[] | Record<string, unknown> | string> : Force extends "stringOrNumber" ? Array<string | boolean | bigint | symbol | null | undefined | Record<string, unknown> | AnyFunction | unknown[] | Date | RegExp | Map<unknown, unknown> | Set<unknown> | Promise<unknown>> : Force extends "primitives" ? Array<string | symbol | Record<string, unknown> | AnyFunction | unknown[] | Date | RegExp | Map<unknown, unknown> | Set<unknown> | Promise<unknown>> : Force extends false ? Array<string | number | bigint | boolean | symbol | RegExp | Record<string, unknown> | AnyFunction | Date | Map<unknown, unknown> | Set<unknown> | Promise<unknown> | unknown[] | null | undefined> : unknown[]; type ResFTN<Force extends false | "stringOrNumber" | "primitives" | "all" = false> = Force extends "all" ? Array<string | Record<string, unknown>> : Force extends "stringOrNumber" ? Array<string | boolean | bigint | symbol | null | undefined | Record<string, unknown> | AnyFunction | Date | RegExp | Promise<unknown>> : Force extends "primitives" ? Array<string | symbol | RegExp | Record<string, unknown> | AnyFunction | Date | Promise<unknown>> : Force extends false ? Array<string | number | bigint | boolean | symbol | RegExp | Record<string, unknown> | AnyFunction | Date | Promise<unknown> | null | undefined> : unknown[]; type DedupeResult<Force extends ForceToStringOptions = false, FTN extends boolean = false> = FTN extends false ? ResUnFTN<Force> : ResFTN<Force>; type ForceToStringOptions = false | "stringOrNumber" | "primitives" | "all"; type DedupeArrayOptions<F extends ForceToStringOptions, Fl extends boolean> = { /** Enables string conversion for comparison, default is `false`. * * @default false * @type {ForceToStringOptions} */ forceToString?: F; /** If true, deeply flattens `Arrays`, `Maps`, and `Sets` before deduplication, default is `false`. * * @default false */ flatten?: Fl; }; /** ---------------------------------------------------------- * * ***Utility: `dedupeArray`.*** * --------------------------------------------- * **Deduplicates values in an array (with optional flattening and deep stringification).** * - Supports various modes for converting values to strings before deduplication: * - `"stringOrNumber"`: Converts strings and numbers to strings. * - `"primitives"`: Converts all primitives (string, number, boolean, bigint, null, undefined, NaN) to strings. * - `"all"`: Converts all values (primitives, objects, Maps, Sets, Symbols, RegExp, Dates, Errors, Promises, functions) * to strings, including nested object properties. * - `false` (default): No conversion applied. * - Options: * - `forceToString`: Enables string conversion for comparison, default is `false`. * - `flatten`: If true, deeply flattens arrays, Maps, and Sets before deduplication, default is `false`. * @template ForceToString - `forceToString` mode. * @template Flattening - `flatten` mode. * @param {unknown[]} inputArray - The array to deduplicate, can be deeply nested and contain any mix of types. * @param {DedupeArrayOptions<ForceToString, Flattening>|undefined} [options] - Options to control string conversion. * @returns {DedupeResult<ForceToString, Flattening>} Deduplicated array with optional transformations. * @throws **{@link TypeError | `TypeError`}** if the input is not an array, or options is not an object, or if `forceToString` is invalid. * @example * ```ts * dedupeArray(["apple", "banana", "apple"]); * // ➔ ["apple", "banana"] * dedupeArray([[1, 2], [1, 2]], { flatten: true }); * // ➔ [1, 2] * dedupeArray([new Set([1, 2]), new Set([2, 3])], { flatten: true }); * // ➔ [1, 2, 3] * dedupeArray([1, "1", 2, "2"], { * forceToString: "stringOrNumber" * }); // ➔ ["1", "2"] * dedupeArray([true, "true", false, undefined], { * forceToString: "primitives" * }); // ➔ ["true", "false", "undefined"] * dedupeArray([1, "1", { a: 1 }], { * forceToString: "all" * }); // ➔ ["1", { a: "1" }] * dedupeArray([1, 1, [2, 2, [3, 3]]]); * // ➔ [1, [2, [3]]] * dedupeArray([null, undefined, null]); * // ➔ [null, undefined] * dedupeArray([[], [[]], [[[]]], [[]], [[[]]]]); * // ➔ [[], [[]], [[[]]]] * const fn = () => 1; * dedupeArray([fn, fn, () => 1]); * // ➔ [fn, () => 1] cause: ref () => 1 and fn is different but ref const `fn` and `fn` is same ref. * dedupeArray([Symbol("x"), Symbol("x")]); * // ➔ [Symbol("x")] (symbols are same by identity, so dedupe * dedupeArray([NaN, NaN, 1, "1"]); * // ➔ [NaN, 1, "1"] * dedupeArray([NaN, NaN, 1, "1"], { * forceToString: "primitives" * }); // ➔ ["NaN", "1"] * dedupeArray([new Date("2025-01-01"), new Date("2025-01-01")]); * // ➔ [Date("2025-01-01")] (same time, deduped) * dedupeArray([new Date("2025-01-01"), new Date("2025-01-01")], { * forceToString: "all" * }); // ➔ ["2025-01-01T00:00:00.000Z"] * dedupeArray([/abc/, /abc/], { * forceToString: "all" * }); // ➔ ["/abc/"] * dedupeArray([new Map(), new Set(), new Error("err")], { * forceToString: "all" * }); // ➔ ["[object Map]", "[object Set]", "Error: err"] * dedupeArray([Promise.resolve(1), Promise.resolve(1)], { * forceToString: "all" * }); // ➔ ["[object Promise]"] * dedupeArray([{ a: 1 }, { a: 1 }, { a: 2 }], { * forceToString: "primitives" * }); // ➔ [{ a: "1" }, { a: "2" }] * dedupeArray([{ a: { b: 1 } }, { a: { b: 1 } }], { * forceToString: "all" * }); // ➔ [{ a: { b: "1" } }] * dedupeArray("not an array"); * // ➔ Throws TypeError * dedupeArray([1, 2, 3], { * forceToString: "invalid" * }); // ➔ Throws TypeError * ``` */ declare const dedupeArray: <ForceToString extends ForceToStringOptions = false, Flattening extends boolean = false>(inputArray: unknown[], options?: DedupeArrayOptions<ForceToString, Flattening>) => DedupeResult<ForceToString, Flattening>; type ExcludeNil<T> = Exclude<T, null | undefined>; /** ---------------------------------------------------------- * * ***Element extractor*** * ---------------------------------------------------------- */ type ElementOf<A extends readonly unknown[]> = A extends readonly (infer U)[] ? U : never; /** ---------------------------------------------------------- * * ***Compute `FilterNilArray`*** * ---------------------------------------------------------- * * for a tuple/array A by using the element type (without null|undefined). * */ type FilterNilArrayFromTuple<A extends readonly unknown[]> = FilterNilArray<ExcludeNil<ElementOf<A>>>; /** ---------------------------------------------------------- * ***Preserve `mutability`: if A is mutable (extends unknown[]), keep B; otherwise make B readonly***. */ type PreserveMutability<A extends readonly unknown[], B> = A extends unknown[] ? B : Readonly<B>; type IsDeepEmptyArray<T> = T extends readonly [] ? true : T extends readonly (infer U)[] ? IsDeepEmptyArray<U> : false; type FilterNilRecursive<T> = T extends readonly (infer U)[] ? T extends (infer U)[] ? FilterNilRecursive<ExcludeEmptyArray<U>>[] : readonly FilterNilRecursive<ExcludeEmptyArray<U>>[] : Exclude<T, null | undefined>; type ExcludeEmptyArray<T> = T extends [] ? never : T; type NormalizerArrays<T> = NormalizeEmptyArraysRecursive<RemoveEmptyArrayElements<FilterNilRecursive<T[]>>>; type FilterNilArray<T> = IsDeepEmptyArray<NormalizerArrays<T>> extends true ? [] : FixNeverArrayRecursive<NormalizerArrays<T>>; /** ---------------------------------------------------------- * * ***Utility: `filterNilArray`.*** * --------------------------------------------- * **Removes `null` and `undefined` values from an array, including nested arrays.** * - **Behavior:** * - Returns `undefined` if the input is explicitly `undefined` or `null`. * - Returns `[]` if input is empty or all elements are removed after filtering. * - Recursively filters nested arrays while preserving structure. * - Ensures proper type inference for safer downstream operations. * @template A - The type of elements in the array. * @param {T[]|null|undefined} input - The array to be filtered. * @returns {T[] | undefined} A new array with `null` and `undefined` values removed, * or `undefined` if the input is explicitly `undefined` or `null`. * @example * ```ts * filterNilArray([1, null, 2, undefined, 3]); * // ➔ [1, 2, 3] * filterNilArray([null, undefined]); * // ➔ [] * filterNilArray(undefined); * // ➔ undefined * filterNilArray(null); * // ➔ undefined * filterNilArray([]); // or * filterNilArray([[[]]]); // or * filterNilArray([[[],undefined,null]]); * // ➔ [] * filterNilArray([1, [null, 2, [undefined, 3]]]); * // ➔ [1, [2, [3]]] * ``` */ declare function filterNilArray(input: null | undefined): undefined; declare function filterNilArray<A extends readonly unknown[]>(input: A): PreserveMutability<A, FilterNilArrayFromTuple<A>>; declare function filterNilArray<A extends readonly unknown[]>(input: A | null | undefined): PreserveMutability<A, FilterNilArrayFromTuple<A>> | undefined; declare function filterNilArray<A>(input: (A | null | undefined)[] | null | undefined): FilterNilArray<A> | undefined; declare function filterNilArray(input: readonly unknown[] | null | undefined): unknown[] | undefined; declare function filterNilArray(input: unknown[]): unknown[]; /** --------------------------------- * * ***Utility: `toBooleanContent`.*** * --------------------------------------------- * **Converts a given value into a boolean (***strict***).** * - **This is stricter than normal JS coercion:** * - `null` and `undefined` return `false`. * - Empty strings return `false`, non-empty strings return `true`. * - Numbers: `0` is `false`, others `true`. * - Booleans returned as-is. * - Arrays: `[]` is `false`, non-empty is `true`. * - Objects: `{}` is `false`, object with keys is `true`. * @param {*} value - The value to be converted. * @returns {boolean} Return `true` if the value is considered non-empty, otherwise `false`. * @example * toBooleanContent(null); // ➔ false * toBooleanContent(undefined); // ➔ false * toBooleanContent(""); // ➔ false * toBooleanContent(" "); // ➔ false * toBooleanContent("abc"); // ➔ true * toBooleanContent(" asd "); // ➔ true * toBooleanContent(0); // ➔ false * toBooleanContent(42); // ➔ true * toBooleanContent(NaN); // ➔ true * toBooleanContent([]); // ➔ false * toBooleanContent([1]); // ➔ true * toBooleanContent({}); // ➔ false * toBooleanContent({ a: 1 }); // ➔ true * toBooleanContent({[Symbol("key")]: 123}); // ➔ false */ declare const toBooleanContent: (value: unknown) => boolean; /** ------------------------------------------------- * * ***Utility: `toBooleanContentDeep`.*** * --------------------------------------------- * **This function does a deep inspection to determine if the input * contains any meaningful / non-empty value.** * @description * It is stricter than JavaScript's normal truthy checks because it looks *inside* * nested arrays & objects (recursively checks). * - **Rules:** * - `null` and `undefined` return `false` * - Empty strings `""` return `false` * - `0` returns `false` * - Empty arrays `[]` or empty objects `{}` return `false` * - Checks deeply nested arrays/objects — if any value inside is "non-empty", returns `true` * @param {*} value - The value to check. * @returns {boolean} Return `true` if the value or anything nested inside is non-empty, otherwise `false`. * @example * toBooleanContentDeep(null); // ➔ false * toBooleanContentDeep(""); // ➔ false * toBooleanContentDeep(0); // ➔ false * toBooleanContentDeep([]); // ➔ false * toBooleanContentDeep({}); // ➔ false * toBooleanContentDeep([[], {}]); // ➔ false * toBooleanContentDeep("abc"); // ➔ true * toBooleanContentDeep(42); // ➔ true * toBooleanContentDeep(NaN); // ➔ true * toBooleanContentDeep([0, "", 5]); // ➔ true * toBooleanContentDeep([NaN, "", 0]); // ➔ true * toBooleanContentDeep([0, "", null]); // ➔ false * toBooleanContentDeep({ a: 0 }); // ➔ false * toBooleanContentDeep({ a: 1 }); // ➔ true * toBooleanContentDeep({ a: { b: [] }}); // ➔ false * toBooleanContentDeep({ a: { b: "x" }}); // ➔ true * toBooleanContentDeep({[Symbol("key")]: 123}); // ➔false */ declare const toBooleanContentDeep: (value: unknown) => boolean; type ToBooleanExplicitOptions = { /** Whether string comparison ignores case, _defaultValue: `false`_. * * @default false */ caseInsensitive?: boolean; /** Whether to trim whitespace before comparison, _defaultValue: `true`_. * * @default true */ trimString?: boolean; /** Whether to consider the string `"indeterminate"` as `true`, _defaultValue: `false`_. * * @default false */ includeIndeterminate?: boolean; }; /** --------------------------------- * * ***Utility: `toBooleanExplicit`.*** * --------------------------------------------- * **Converts a value into a strict boolean.** * - **Behavior:** * - It supports various common string representations of truthy values, * including `"true"`, `"on"`, `"yes"`, `"1"`, the number `1`, the boolean `true`, * and optionally the string `"indeterminate"` if enabled. * - **ℹ️ Note:** * - Any other value, including `undefined`, `null`, `false`, `0`, and * unrecognized strings will return `false`. * - Supports optional `caseInsensitive` and `trimString` to customize * string normalization. * @param {*} value - The value to convert. * @param {ToBooleanExplicitOptions} [options] - Options for conversion behavior. * @param {ToBooleanExplicitOptions["caseInsensitive"]} [options.caseInsensitive=false] - Whether string comparison ignores case, default: `false`. * @param {ToBooleanExplicitOptions["trimString"]} [options.trimString=true] - Whether to trim whitespace before comparison, default: `true`. * @param {ToBooleanExplicitOptions["includeIndeterminate"]} [options.includeIndeterminate=false] - If `true`, the string `"indeterminate"` is considered a truthy value, defaults to `false`. * @returns {boolean} Return `true` if the value matches a truthy representation, otherwise `false`. * @throws **{@link TypeError | `TypeError`}** if any option provided is not a boolean. * @example * toBooleanExplicit(1); * // ➔ true * toBooleanExplicit(true); * // ➔ true * toBooleanExplicit("on"); * // ➔ true * toBooleanExplicit("1"); * // ➔ true * toBooleanExplicit(0); * // ➔ false * toBooleanExplicit("off"); * // ➔ false * toBooleanExplicit("Yes"); * // ➔ false (caseInsensitive is false by default) * toBooleanExplicit(" yes "); * // ➔ true (whitespace trimmed by default) * toBooleanExplicit("YES", { caseInsensitive: true }); * // ➔ true * toBooleanExplicit("YES", { caseInsensitive: false }); * // ➔ false * toBooleanExplicit(" YES ", { trimString: false }); * // ➔ false (whitespace not trimmed) * toBooleanExplicit(" YES ", { trimString: true, caseInsensitive: true }); * // ➔ true * toBooleanExplicit(" YES ", { trimString: true, caseInsensitive: false }); * // ➔ false * toBooleanExplicit("indeterminate"); * // ➔ false (default) * toBooleanExplicit("indeterminate", { includeIndeterminate: true }); * // ➔ true */ declare const toBooleanExplicit: (value: unknown, options?: ToBooleanExplicitOptions) => boolean; /** --------------------------------- * * ***Utility: `toBooleanLoose`.*** * --------------------------------------------- * **Converts a given value into a boolean (loose).** * - **This follows JavaScript's typical truthy/falsy rules with some tweaks:** * - `null` and `undefined` return `false`. * - Empty strings return `false`, non-empty strings return `true`. * - Numbers: `0` is `false`, others `true`. * - Booleans returned as-is. * - Arrays: `[]` is `false`, non-empty is `true`. * - Other objects: uses `Boolean(value)`, so `{}` is `true`. * @param {*} value - The value to be converted. * @returns {boolean} Return `true` if the value is truthy, otherwise `false`. * @example * toBooleanLoose(null); // ➔ false * toBooleanLoose(""); // ➔ false * toBooleanLoose("abc"); // ➔ true * toBooleanLoose(0); // ➔ false * toBooleanLoose(42); // ➔ true * toBooleanLoose([]); // ➔ false * toBooleanLoose([1]); // ➔ true * toBooleanLoose({}); // ➔ true * toBooleanLoose({ a: 1 }); // ➔ true */ declare const toBooleanLoose: (value: unknown) => boolean; /** ------------------------------------------------------------- * * ***Utility: `parseCurrencyString`.*** * --------------------------------------------- * **Parses a human-friendly currency string into a JavaScript number.** * - **Supports multi-locale formats:** * - ***US:*** `"15,000.10"` ➔ `15300.10`. * - ***Swiss:*** `"15'000.10"` ➔ `15300.10`. * - ***French:*** `"15 000,10"` ➔ `15300.10`. * - ***Indian:*** `"1,23,456.78"` ➔ `123456.78`. * - ***European:*** `"151.000,10"` ➔ `151300.10`. * - ***Compact:*** `"15300000,10"` ➔ `15300000.10`. * - **Features:** * - Strips symbols automatically: `"Rp"`, `"$"`, `"EUR"`, `etc`. * - Handles bracket negatives: `"(15.000,10)"` ➔ `-15300.10`. * - Normalizes decimal separator (last dot or comma). * - Detects non-breaking spaces (`\u00A0`, `\u202F`) often in European data. * - Fallback to `0` for empty, invalid, or non-numeric strings. * - **How it parses internally:** * 1. Removes all characters except digits, `.`, `,`, `'`, `space`, * `\u00A0`, `\u202F`. * 2. Detects bracket (...) as negative. * 3. If Indian style (`1,23,456`) detected by multiple ,`\d{2}`, removes all commas. * 4. Otherwise: * - If multiple dots & no commas ➔ thousands: removes all `.`. * - If multiple commas & no dots ➔ thousands: removes all `,`. * - If mixed, treats last `,` or `.` as decimal. * 5. Converts final decimal to `.` for JS float. * - **Gotchas:** * - If both `.` and `,` are present, last occurrence is used as decimal. * - For strings like `"1.121.234,56"` ➔ decimal is `,`. * - For `"1,121,234.56"` ➔ decimal is `.`. * - For `"15300000,2121"` ➔ decimal becomes `.` internally. * - **ℹ️ Note:** * - You can use this function as a first step to **sanitize currency inputs** * before storing into database or doing math. * - Always pair this with your formatter for consistent output display. * @param {string|null|undefined} input * ***Any messy currency string, may contain:*** * * Currency symbols (`Rp`,`$`, `CHF`, `EUR`). * * Thousands separators (`.`, `,`, `'`, `space`, `\u00A0`, `\u202F`). * * Various decimal formats (`,` or `.`). * * Bracket negative: `"(15.000,10)"`. * @returns {number} JavaScript float representation, will return `0` for invalid, empty, or non-string input. * @example * ```ts * parseCurrencyString("Rp 15.300.000,21"); * // ➔ 15300000.21 * parseCurrencyString("15 300 000,21"); * // ➔ 15300000.21 * parseCurrencyString("CHF 15'300'000.21"); * // ➔ 15300000.21 * parseCurrencyString("$15,300,000.21"); * // ➔ 15300000.21 * parseCurrencyString("(15.000,10)"); * // ➔ -15000.10 * parseCurrencyString("1,23,456.78"); * // ➔ 123456.78 * parseCurrencyString("15300000,2121"); * // ➔ 15300000.2121 * parseCurrencyString("USD 15 300 000.21"); * // ➔ 15300000.21 * parseCurrencyString(""); * // ➔ 0 * parseCurrencyString("abc"); * // ➔ 0 * ``` */ declare const parseCurrencyString: (input: string | null | undefined) => number; /** ---------------------------------------------------------- * * ***Utility: `convertType`.*** * --------------------------------------------- * **Converts a value from a string to its corresponding JavaScript primitive type.** * - **Supported conversions for string inputs (case-insensitive, trimmed):** * - `"true"` ➔ `true` (***boolean***). * - `"false"` ➔ `false` (***boolean***). * - `"null"` ➔ `null` (***null***). * - `"yes"` ➔ `true` (***boolean***). * - `"no"` ➔ `false` (***boolean***). * - `"nan"` or `"NaN"` ➔ `NaN` (***number***). * - `"undefined"` ➔ `undefined` (***undefined***). * - Numeric strings with optional thousands separators (e.g. `"3,567,890.14"`) ➔ `3567890.14` ***as a `number` type***. * - Strings containing only whitespace are converted to empty string `""`. * - Non-string inputs are returned unchanged. * - Strings not matching any special case are trimmed and returned as-is. * @param {*} value - The value to convert, usually a string or other type. * @returns {*} The converted JavaScript primitive (***`boolean`***, ***`number`***, ***`null`***, ***`undefined`***, ***`NaN`***) or the original value if no conversion applies. * @example * convertType("true"); // ➔ true * convertType(" 42 "); // ➔ 42 * convertType("FALSE"); // ➔ false * convertType(" null "); // ➔ null * convertType(" "); // ➔ "" * convertType(" Hello World "); // ➔ "Hello World" * convertType("NaN"); // ➔ NaN * convertType(100); // ➔ 100 * convertType(NaN); // ➔ NaN * convertType({}); // ➔ {} */ declare const convertType: (value: unknown) => unknown; /** -------------------------------------------------- * * ***Options for cleaning and transforming parsed JSON data.*** * -------------------------------------------------- * * @private Type Options Validation for Function: {@link cleanParsedData | `cleanParsedData`}, {@link parseCustomDate | `parseCustomDate`} and {@link safeJsonParse | `safeJsonParse`}. */ type ParseParsedDataOptions = { /** -------------------------------------------------- * * ***Convert numeric strings to numbers (e.g., `"42"` ➔ `42`), defaultValue: `false`.*** * -------------------------------------------------- * * @default false */ convertNumbers?: boolean; /** -------------------------------------------------- * * ***Convert numeric strings `"NaN"` to `NaN` (e.g., `"NaN"` ➔ `NaN`), defaultValue: `false`.*** * -------------------------------------------------- * * @default false */ convertNaN?: boolean; /** -------------------------------------------------- * * ***Convert `"true"` / `"false"` strings to boolean values, defaultValue: `false`.*** * -------------------------------------------------- * * @default false */ convertBooleans?: boolean; /** -------------------------------------------------- * * ***Convert valid date strings into `Date` objects, defaultValue: `false`.*** * -------------------------------------------------- * * @default false */ convertDates?: boolean; /** -------------------------------------------------- * * ***Custom date formats to be parsed (e.g., `["DD/MM/YYYY", "MM/DD/YYYY"]`), defaultValue: `[]`.*** * -------------------------------------------------- * * @default [] */ customDateFormats?: string[]; /** -------------------------------------------------- * * ***Remove `null` values from objects and arrays, defaultValue: `false`.*** * -------------------------------------------------- * * @default false */ removeNulls?: boolean; /** -------------------------------------------------- * * ***Remove `undefined` values from objects and arrays, defaultValue: `false`.*** * -------------------------------------------------- * * - ***Behavior:*** * - `false` (**default**): replaces `undefined` with `null`. * - `true`: removes keys with `undefined` values. * * @default false */ removeUndefined?: boolean; /** -------------------------------------------------- * * ***Remove empty objects `{}` from the final output, defaultValue: `false`.*** * -------------------------------------------------- * * @default false */ removeEmptyObjects?: boolean; /** -------------------------------------------------- * * ***Remove empty arrays `[]` from the final output, defaultValue: `false`.*** * -------------------------------------------------- * * @default false */ removeEmptyArrays?: boolean; /** -------------------------------------------------- * * ***Removes values that do not match selected conversions, defaultValue: `false`.*** * -------------------------------------------------- * * @default false */ strictMode?: boolean; /** -------------------------------------------------- * * ***Enable error logging if JSON parsing fails, defaultValue: `false`.*** * -------------------------------------------------- * * @default false */ loggingOnFail?: boolean; /** -------------------------------------------------- * * ***Custom error handler function.*** * -------------------------------------------------- * * - ***Behavior:*** * - If provided, it will be called with the error. * - If not provided, defaults to `undefined` in type, but internally a no-op function is used. * * @param error - Error instance thrown during fail on execution. * @default undefined */ onError?: (error: Error) => void; /** -------------------------------------------------- * * ***Whether to check symbol properties when checking empty objects.*** * -------------------------------------------------- * * @default false */ checkSymbols?: boolean; }; /** -------------------------------------------------- * * ***Utility: `cleanParsedData`.*** * --------------------------------------------- * **Cleans parsed JSON data based on provided options.** * @template T - Expected output type. * @param {*} data - The parsed JSON data. * @param {ParseParsedDataOptions} [options] - The cleaning options. * @returns {T | null | undefined} The cleaned data. * - ***⚠️ Notice:*** _If data is JSON string, we recommend use ***`safeJsonParse` utility function*** for more safe._ * - ***⚠️ Note:*** _If using **`convertDates`** **options**, result may contain Date objects, you may need type assertions in strict TypeScript settings._ * @example * ```ts * // 1: Convert numbers and remove nulls * const result = cleanParsedData({ age: "25", name: null }, { * convertNumbers: true, * removeNulls: true * }); * console.log(result); // ➔ { age: 25 } * // 2: Convert boolean strings * const result = cleanParsedData({ isActive: "true" }, { * convertBooleans: true * }); * console.log(result); // ➔ { isActive: true } * ``` */ declare const cleanParsedData: <T = unknown>(data: T, options?: ParseParsedDataOptions) => T | undefined | null; /** -------------------------------------------------- * * ***Utility: `parseCustomDate`.*** * --------------------------------------------- * **Parses custom date formats like "DD/MM/YYYY" or "MM/DD/YYYY".** * @param {string} dateString - Date string to parse. * @param {string} format - Date format to match. * @returns {Date | null} Returns a `Date` object if valid, otherwise `null`. * @throws **{@link TypeError | `TypeError`}** if `dateString` **(first parameter)** and `format` **(second parameter)** is not a string or empty-string. * @example * // Valid: European format (DD/MM/YYYY) * const date1 = parseCustomDate("03/09/2025", "DD/MM/YYYY"); * console.log(date1); // ➔ Date { Wed Sep 03 2025 ... } * * // Valid: US format (MM/DD/YYYY) * const date2 = parseCustomDate("09/03/2025", "MM/DD/YYYY"); * console.log(date2); // ➔ Date { Wed Sep 03 2025 ... } * * // Invalid: wrong format * const date3 = parseCustomDate("2025-09-03", "DD/MM/YYYY"); * console.log(date3); // ➔ null * * // Invalid: non-date string * const date4 = parseCustomDate("hello", "DD/MM/YYYY"); * console.log(date4); // ➔ null * * // Throws: wrong parameter types or empty-string * parseCustomDate(123, "DD/MM/YYYY"); * // ➔ TypeError: Parameter `dateString` and `format` must be of type `string`... */ declare const parseCustomDate: (dateString: string, format: string) => Date | null; type NonJsonParsableType = Omit<Exclude<unknown, string | null | undefined>, string>; type Contains<T, U> = [Extract<T, U>] extends [never] ? false : true; /** @private ***The value type for the overload function {@link safeJsonParse | `safeJsonParse`}.*** */ type UnknownValue = { undefined: true; }; /** @private ***The narrows type result for {@link safeJsonParse | `safeJsonParse`}.*** */ type SafeJsonParseResult<TData, T> = IfNotExtends<T, NonJsonParsableType> extends true ? T extends never ? undefined : T extends void ? undefined : T extends number ? undefined : Contains<T, string> extends true ? Contains<T, null & string> extends true ? TData | null | undefined : TData | undefined : IfExtends<T, null> extends true ? null : IfNotExtends<T, NonJsonParsableType> extends true ? TData | null | undefined : undefined : Contains<T, string> extends true ? IsAny<T> extends true ? TData | undefined | null : TData | undefined : undefined; /** -------------------------------------------------- * * ***Utility: `safeJsonParse`.*** * --------------------------------------------- * **Safely parses JSON while handling errors and applying transformations.** * - **Supports generics** to ensure accurate return type inference. * - Always provide both `<TData, TInput>` for best results. * - ℹ️ ***Scroll down for full generic behavior explanation.*** * - Automatically parses valid JSON strings into `objects`, `arrays`, `numbers`, etc. * - Supports data transformation via options (e.g., convert strings to `numbers`, `booleans`, or `dates`). * - **Returns:** * 1. `null` ➔ if input is explicitly `null`. * 2. `undefined` ➔ if input is `undefined`, not a `string`, or if parsing fails. * 3. Parsed and cleaned result (`TData`) ➔ if input is a valid JSON string. * - ⚠️ **JSON.stringify note**: * - _If the input JSON string was created using `JSON.stringify()`, any properties with `undefined` * values would have been automatically removed or converted to `null` depending on the serializer, example:_ * ```ts * JSON.stringify({ a: undefined, b: 1 }); // ➔ '{"b":1}' * JSON.parse('{"a": undefined, "b": 1}') // ❌ invalid JSON * ``` * _Therefore, if you see `undefined` in raw input, it will likely throw unless pre-cleaned or replaced with `null`._ * * ```ts * safeJsonParse('{"name": "John", "score": undefined}'); * // result ➔ { name: "John", score: null } <- because `undefined` is not valid JSON, gets replaced to null. * ``` * - ℹ️ **Additionally:** * - This function normalizes single quotes (`'`) to double quotes (`"`) before parsing, * so JSON strings using single quotes will be converted to valid JSON format, example: * ```ts * safeJsonParse("{'name': 'John', 'age': 30}"); * // result ➔ { name: "John", age: 30 } * * safeJsonParse("{'string\\'s': 'abc', \"quote's\": 'It\\'s awesome!', 'aNumber\\'s': 123, 'keyWith\\'Backslash\\'s': 'value\\'s'}"); * // result ➔ { "string's": "abc", "quote's": "It's awesome!", "aNumber's": 123, "keyWith'Backslash's": "value's" } * ``` * @template TData - The expected output type after parsing and cleaning. * @template TInput - The input value type, used for advanced type inference and return typing. * @param {TInput} [value] - The JSON string or value to parse. * @param {ParseParsedDataOptions} [options] - Options to clean, convert types, enable strict mode, * support custom date formats, enable logging, or handle errors via callback. * @returns {SafeJsonParseResult<TData, TInput>} Parsed and optionally cleaned result, or `null`/`undefined`. * @throws **{@link TypeError | `TypeError`}** if `options` is provided but not a valid object. * @example * 1. ***Basic parse with number & boolean conversion:*** * ```ts * const result = safeJsonParse(30); * // result ➔ undefined * const result = safeJsonParse(30, { * convertNumbers: true * }); * // result ➔ 30 * * const result = safeJsonParse('{"age": "30", "isActive": "true"}', { * convertNumbers: true, * convertBooleans: true * }); * // result ➔ { age: 30, isActive: true } * ``` * 2. ***Handling `undefined` in input string (manually written, not JSON.stringify):*** * ```ts * const result = safeJsonParse('{"score": undefined}'); * // result ➔ { score: null } <- because `undefined` is not valid JSON, gets replaced * ``` * * 3. ***Handling `NaN` in input string (manually written, not JSON.stringify):*** * ```ts * const value = NaN; // <- value is NaN or "NaN"; * const result = safeJsonParse(value); * // result ➔ undefined <- will return as undefined, because options `convertNaN` is false (default), * const result2 = safeJsonParse(value, { convertNaN: true }); * // result2 ➔ NaN <- will return as undefined because options `convertNaN` is false, * * const result4 = safeJsonParse('{"strNan": "NaN", "pureNan": NaN}'); * // NaN will convert to string (NaN ➔ "NaN") because options `convertNaN` is false (default), * // result4 ➔ { strNan: "NaN", pureNan: "NaN" } * * const result3 = safeJsonParse('{"strNan": "NaN", "pureNan": NaN}', { * convertNaN: true * }); * // String "NaN" will convert to NaN ("NaN" ➔ NaN) because options `convertNaN` is true, * // result3 ➔ { strNan: NaN, pureNan: NaN } * ``` * * 4. ***Strict mode (removes invalid values):*** * ```ts * const result = safeJsonParse('{"name": " ", "score": "99abc"}', { * convertNumbers: true, * strictMode: true * }); * // result ➔ {} * * const result2 = safeJsonParse('{"name": " ", "score": undefined}'); * // result2 ➔ { name: "",score: null } * ``` * * 5. ***Custom date format parsing:*** * ```ts * const result = safeJsonParse('{"birthday": "25/12/2000"}', { * convertDates: true, * customDateFormats: ["DD/MM/YYYY"] * }); * // result ➔ { birthday: new Date("2000-12-25T00:00:00.000Z") } * ``` * * 6. ***Invalid JSON with custom error handling:*** * ```ts * safeJsonParse("{invalid}", { * loggingOnFail: true, * onError: (err) => console.log("Custom handler:", err.message) * }); * // ➔ Logs parsing error and invokes handler * ``` * * 7. ***Null or non-string input returns null/undefined (default options):*** * ```ts * safeJsonParse(123); // ➔ undefined * safeJsonParse(null); // ➔ null * safeJsonParse(undefined); // ➔ undefined * ``` * * 8. ***Generic usage: Provide both output and input type to ensure correct return typing:*** * ```ts * type UserType = { name: string }; * * const obj = JSON.stringify({ * name: "John" * }); * * const toParse = isAuth() ? obj : null; * const toParse2 = isAuth() ? obj : undefined; * * // * `Without Generic`: * const parsed = safeJsonParse(toParse); * //- runtime: { name: "John" } | undefined | null * //- type: Record<string, unknown> | undefined | null * const parsed2 = safeJsonParse(toParse); * //- runtime: { name: "John" } | undefined * //- type: Record<string, unknown> | undefined * * // * `With Generic`: * const parsed = safeJsonParse<UserType>(toParse); * //- runtime: { name: "John" } | undefined | null * //- type: undefined <- (⚠️ unexpected!) * const parsed2 = safeJsonParse<UserType>(toParse); * //- runtime: { name: "John" } | undefined * //- type: undefined <- (⚠️ unexpected!) * const parsed = safeJsonParse<UserType, typeof toParse>(toParse); * //- runtime: { name: "John" } | null | undefined * //- type: UserType | null | undefined * const parsed2 = safeJsonParse<UserType, typeof toParse>(toParse); * //- runtime: { name: "John" } | undefined * //- type: UserType | undefined * ``` * @note * ⚠️ **Generic Behavior:** * - This function supports advanced generic inference for clean, type-safe return values. * - If only the first generic (`TData`) is provided and the second (`TInput`) is omitted, * then `TInput` defaults to `undefined`, resulting in a return type of `undefined`. * - To ensure correct return typing, **always pass both generics** when `value` is dynamic, * nullable, or unioned: `safeJsonParse<TData, typeof value>(value)`. * - This makes the returned type exactly match your expectation: `TData | null | undefined`. */ declare function safeJsonParse<TData extends Record<string, any> = Record<string, unknown>, TInput extends UnknownValue = UnknownValue>(value: TInput, options?: ParseParsedDataOptions): IsAny<TInput> extends true ? TData | null | undefined : undefined; declare function safeJsonParse<TData extends Record<string, any> = Record<string, unknown>, TInput extends string | null | undefined | unknown = undefined>(value: TInput, options?: ParseParsedDataOptions): SafeJsonParseResult<TData, TInput>; /** ---------------------------------------------------------- * * ***Utility: `extractDigits`.*** * --------------------------------------------- * **Extracts digits from a string or number input.** * - **Behavior:** * - Converts the input to a string, trims whitespace, and removes any characters that are not digits (`0-9`). * - Returns the cleaned numeric value as a `number`. * - If the input is a `null`, `undefined`, results in no digits, or not a `string` (or empty-string) or `number`, it safely return `0`. * @param {*} [value] * **The value to process.** * - Accepts a string, number, `null`, or `undefined`. * @returns {number} The numeric value after extracting digits (returns `0` if input is invalid or contains no digits). * @example * extractDigits(12345); // ➔ 12345 * extractDigits("9A8B7C6X1"); // ➔ 98761 * extractDigits("123abc456"); // ➔ 1