interface DeepMergeOptions {
    /**
     * If `true`, arrays will be concatenated instead of replaced.
     * Defaults to `false` (arrays are replaced).
     */
    mergeArrays?: boolean;
}

/**
 * Recursively merges properties from `source` object into `target` object.
 * This function is immutable, meaning it returns a new object and does not mutate the original `target` or `source` objects.
 * It performs a deep merge for plain objects. Other object types (like Dates, RegExps, class instances)
 * are replaced by their source counterpart if they exist in `source`, otherwise, the target's version is kept.
 * Arrays are replaced by the source array by default, or concatenated if `mergeArrays` option is `true`.
 *
 * @template T The type of the target object.
 * @template U The type of the source object.
 * @param target The target object.
 * @param source The source object to merge from.
 * @param options
 * @returns A new object with properties from `source` deep merged into `target`.
 *
 * @example
 * const obj1 = { a: 1, b: { c: 2 }, d: [1, 2] };
 * const obj2 = { b: { e: 3 }, d: [3, 4], f: 5 };
 *
 * deepMerge(obj1, obj2);
 * // => { a: 1, b: { c: 2, e: 3 }, d: [3, 4], f: 5 } (arrays are replaced)
 *
 * deepMerge(obj1, obj2, { mergeArrays: true });
 * // => { a: 1, b: { c: 2, e: 3 }, d: [1, 2, 3, 4], f: 5 } (arrays are concatenated)
 *
 * const obj3 = { date: new Date('2023-01-01') };
 * const obj4 = { date: new Date('2024-01-01'), other: 'value' };
 * deepMerge(obj3, obj4);
 * // => { date: [Date object from obj4], other: 'value' } (Date object is replaced)
 */
declare function deepMerge<T extends object | null | undefined, U extends object | null | undefined>(target: T, source: U, options?: DeepMergeOptions): (T extends object ? T : {}) & (U extends object ? U : {});

export { type DeepMergeOptions, deepMerge, deepMerge as default };
