UNPKG

funtool

Version:

A modern, efficient, and modular JavaScript utility library designed to enhance developer productivity.

217 lines (213 loc) 7.96 kB
/** * A customizer function for `cloneWith`, used to transform values before cloning. * - If the customizer returns `undefined`, the default clone logic will be used. * - If a value is returned, it will be used instead of the default clone. */ type Customizer<T> = T extends any[] ? (val: T[number], index: number) => T[number] | undefined : T extends object ? (val: T[keyof T], key: keyof T) => T[keyof T] | undefined : never; /** * Creates a shallow clone of the given value. * * Supports a wide range of built-in JavaScript types including: * - Primitives (returned as-is) * - Arrays * - Date objects * - RegExp objects * - Map and Set * - TypedArrays (e.g. Uint8Array, Float32Array, etc.) * - DataView * - Plain objects (preserving prototype) * * This function **does not** perform deep cloning. * * @template T - The type of the value to clone * @param {T} value - The value to be cloned * @returns {T} - A shallow copy of the original value * * @example * // Clone an array * const arr = [1, 2, 3]; * const clonedArr = clone(arr); * console.log(clonedArr); // [1, 2, 3] * console.log(clonedArr === arr); // ❌ false * * @example * // Clone an object * const obj = { a: 1, b: { c: 2 } }; * const clonedObj = clone(obj); * console.log(clonedObj); // { a: 1, b: { c: 2 } } * console.log(clonedObj === obj); // ❌ false * console.log(clonedObj.b === obj.b); // ✅ true (shallow clone) * * @example * // Clone a Date * const date = new Date(); * const clonedDate = clone(date); * console.log(clonedDate); // Same date as original * console.log(clonedDate === date); // ❌ false * * @example * // Clone a Map * const map = new Map([['key', 'value']]); * const clonedMap = clone(map); * console.log(clonedMap.get('key')); // 'value' * console.log(clonedMap === map); // ❌ false */ declare function clone<T>(value: T): T; /** * Performs a shallow clone of `value`, invoking `customizer` to customize the cloned value. * If `customizer` returns a defined value, it is used instead of the default clone. * * @template T * @param value - The value to clone. * @param customizer - Optional customizer invoked with the value. * @returns {T} The cloned value. * * @example * const obj = { a: 1, b: 2 }; * const result = cloneWith(obj, (val) => typeof val === 'number' ? val + 1 : undefined); * // result => { a: 2, b: 3 } */ declare function cloneWith<T>(value: T, customizer: Customizer<T>): T; type Primitive = string | number | boolean | bigint | symbol | null | undefined; /** * Determines if a type is a Tuple (i.e., fixed-length array) * Tuples have known numeric literal keys and `length` is a constant number. */ type IsTuple<T> = T extends readonly any[] ? number extends T['length'] ? false : true : false; /** * Recursive deep copy type utility. * - Preserves tuples and arrays * - Removes `readonly` from properties * - Recursively copies object properties, including symbol keys */ type CloneDeep<T> = T extends Primitive | ((...args: any[]) => any) ? T : IsTuple<T> extends true ? { [K in keyof T]: CloneDeep<T[K]>; } : T extends ReadonlyArray<infer U> ? Array<CloneDeep<U>> : T extends Map<infer K, infer V> ? Map<K, CloneDeep<V>> : T extends Set<infer U> ? Set<CloneDeep<U>> : T extends Date ? Date : T extends RegExp ? RegExp : T extends object ? { -readonly [K in keyof T]: CloneDeep<T[K]>; } & { [K in keyof T as K extends symbol ? K : never]: CloneDeep<T[K]>; } : T; /** * @description Customizer function type for cloneDeepWith * If it returns `undefined`, cloneDeepWith falls back to default deep cloning logic */ type CloneDeepCustomizer = (value: any, key?: PropertyKey, object?: any) => any; /** * @description Deep copy an object. * Unsupported types like functions, symbols, WeakMap, WeakSet will trigger a warning and return original. * @param {any} obj - The object to deep copy * @param {WeakMap<object, any>} [seen=new WeakMap()] - WeakMap cache to track copied references * @returns {any} - Deep copied object * * @example * const original = { name: "Alice", details: { age: 25 } }; * const copy = cloneDeep(original); * console.log(copy.details.age); // ✅ 25 * console.log(copy !== original); // ✅ true * * @example * const arr = [1, { nested: true }, [3]]; * const copy = cloneDeep(arr); * console.log(copy[1].nested); // ✅ true * * @example * const map = new Map<string, number>([["a", 1], ["b", 2]]); * const copy = cloneDeep(map); * console.log(copy.get("b")); // ✅ 2 * * @example * const set = new Set([1, 2, 3]); * const copy = cloneDeep(set); * console.log(copy.has(2)); // ✅ true * * @example * const date = new Date("2020-01-01"); * const copy = cloneDeep(date); * console.log(copy.getFullYear()); // ✅ 2020 * * @example * const regex = /abc/gi; * const copy = cloneDeep(regex); * console.log(copy.source); // ✅ "abc" * console.log(copy.flags); // ✅ "gi" * * @example * const obj: any = {}; * obj.self = obj; * const copy = cloneDeep(obj); * console.log(copy.self === copy); // ✅ true */ declare function cloneDeep<T>(obj: T, seen?: WeakMap<object, any>): CloneDeep<T>; /** * @description Deep copy with customizer support. * @param {any} obj - The object to clone * @param {CloneDeepCustomizer} customizer - Custom clone handler, can override cloning behavior * @param {WeakMap<object, any>} [seen=new WeakMap()] - Circular reference cache * @returns {any} - Cloned object with possible customization * * @example * const original = { x: new Date(), y: 123 }; * const copy = cloneDeepWith(original, (val) => { * if (val instanceof Date) return 'DATE'; * }); * console.log(copy.x); // ✅ "DATE" */ declare function cloneDeepWith<T>(obj: T, customizer: CloneDeepCustomizer, seen?: WeakMap<object, any>): CloneDeep<T>; /** * Checks if a value exists in an array starting from a given index. * * @template T * @param {T[]} source - The array to search. * @param {T} target - The value to search for. * @param {number} [fromIndex=0] - The index to start searching from. * @returns {boolean} True if found, otherwise false. * @example * includes([1, 2, 3], 2); // ✅ true * includes([1, 2, 3], 2, 2); // ❌ false */ declare function includes<T>(source: T[], target: T, fromIndex?: number): boolean; /** * Checks if a substring exists in a string starting from a given index. * * @param {string} source - The string to search. * @param {string} target - The substring to search for. * @param {number} [fromIndex=0] - The index to start searching from. * @returns {boolean} True if found, otherwise false. * @example * includes('hello world', 'world'); // ✅ true * includes('hello world', 'world', 8); // ❌ false */ declare function includes(source: string, target: string, fromIndex?: number): boolean; /** * Checks if a value exists among the values of an object. * * @param {Record<string, any>} source - The object to search. * @param {*} target - The value to search for. * @returns {boolean} True if found, otherwise false. * @example * includes({ a: 1, b: 2 }, 2); // ✅ true */ declare function includes(source: Record<string, any>, target: any): boolean; /** * Checks if a key exists in a Map. * * @template K, V * @param {Map<K, V>} source - The Map to search. * @param {K} target - The key to search for. * @returns {boolean} True if found, otherwise false. * @example * includes(new Map([['a', 1], ['b', 2]]), 'b'); // ✅ true */ declare function includes<K, V>(source: Map<K, V>, target: K): boolean; /** * Checks if a value exists in a Set. * * @template T * @param {Set<T>} source - The Set to search. * @param {T} target - The value to search for. * @returns {boolean} True if found, otherwise false. * @example * includes(new Set([1, 2, 3]), 2); // ✅ true */ declare function includes<T>(source: Set<T>, target: T): boolean; export { clone, cloneDeep, cloneDeepWith, cloneWith, includes };