Advanced object manipulation including deep cloning, merging, and equality comparison with special handling for React elements, Moment objects, and Immutable.js objects. These utilities are optimized for form data processing and complex object structures.
Fast deep equality comparison with special handling for common JavaScript objects and libraries.
/**
* Perform deep equality comparison between two values
* Handles special cases: React elements, Moment objects, Immutable.js, Date, RegExp, URL objects
* @param a - First value to compare
* @param b - Second value to compare
* @returns True if values are deeply equal
*/
function isEqual(a: any, b: any): boolean;Usage Examples:
import { isEqual } from "@formily/shared";
// Basic equality
console.log(isEqual(1, 1)); // true
console.log(isEqual("hello", "hello")); // true
console.log(isEqual([1, 2, 3], [1, 2, 3])); // true
// Object equality
const obj1 = { a: 1, b: { c: 2 } };
const obj2 = { a: 1, b: { c: 2 } };
const obj3 = { a: 1, b: { c: 3 } };
console.log(isEqual(obj1, obj2)); // true
console.log(isEqual(obj1, obj3)); // false
// Array equality
console.log(isEqual([1, [2, 3]], [1, [2, 3]])); // true
console.log(isEqual([1, [2, 3]], [1, [2, 4]])); // false
// Date equality
const date1 = new Date("2023-01-01");
const date2 = new Date("2023-01-01");
const date3 = new Date("2023-01-02");
console.log(isEqual(date1, date2)); // true
console.log(isEqual(date1, date3)); // false
// RegExp equality
console.log(isEqual(/abc/g, /abc/g)); // true
console.log(isEqual(/abc/g, /abc/i)); // false
// Special handling for React elements (prevents circular reference issues)
import React from "react";
const element1 = React.createElement("div", { id: "test" });
const element2 = React.createElement("div", { id: "test" });
// Compares elements safely without traversing _owner propertiesDeep and shallow cloning operations with special handling for complex objects.
/**
* Create a shallow copy of the value
* Special handling for: React elements, BigNumber, Moment objects, JSON Schema objects, Immutable.js
* @param values - Value to clone
* @returns Shallow copy of the value
*/
function shallowClone(values: any): any;
/**
* Create a deep copy of the value
* Special handling for: React elements, BigNumber, Moment objects, JSON Schema objects, Immutable.js
* @param values - Value to clone
* @returns Deep copy of the value
*/
function clone(values: any): any;Usage Examples:
import { clone, shallowClone } from "@formily/shared";
// Shallow cloning
const original = { a: 1, b: { c: 2 } };
const shallow = shallowClone(original);
shallow.a = 10; // Doesn't affect original
shallow.b.c = 20; // Affects original (shared reference)
console.log(original.a); // 1 (unchanged)
console.log(original.b.c); // 20 (changed, shared reference)
// Deep cloning
const deep = clone(original);
deep.a = 100; // Doesn't affect original
deep.b.c = 200; // Doesn't affect original
console.log(original.a); // 1 (unchanged)
console.log(original.b.c); // 2 (unchanged, separate reference)
// Array cloning
const arr = [1, { x: 2 }, [3, 4]];
const clonedArr = clone(arr);
clonedArr[1].x = 99; // Doesn't affect original
clonedArr[2][0] = 88; // Doesn't affect original
console.log(arr[1].x); // 2 (unchanged)
console.log(arr[2][0]); // 3 (unchanged)
// Special object handling
const moment = require("moment");
const momentObj = moment("2023-01-01");
// These objects are handled specially and returned as-is or converted appropriately
const clonedMoment = clone(momentObj);
const reactElement = React.createElement("div");
const clonedElement = clone(reactElement); // Returns same reference
// Immutable.js objects
const immutableMap = Immutable.Map({ a: 1, b: 2 });
const clonedImmutable = clone(immutableMap); // Calls toJS() methodDeep merging utilities with flexible configuration options.
/**
* Deep merge objects and arrays with configurable options
* @param target - Target object to merge into
* @param source - Source object to merge from
* @param options - Merge configuration options
* @returns Merged result
*/
function merge(target: any, source: any, options?: MergeOptions): any;
/**
* Lazy merge using Proxy for deferred evaluation
* Useful for merging functions or objects that should be evaluated on access
* @param target - Target object/function
* @param args - Additional objects/functions to merge
* @returns Proxy object that merges on property access
*/
function lazyMerge<T extends object | Function>(target: T, ...args: T[]): any;
interface MergeOptions {
arrayMerge?(target: any[], source: any[], options?: MergeOptions): any[];
clone?: boolean;
assign?: boolean;
customMerge?(key: string, options?: MergeOptions): ((x: any, y: any) => any) | undefined;
isMergeableObject?(value: object): boolean;
cloneUnlessOtherwiseSpecified?: (value: any, options: MergeOptions) => any;
}Usage Examples:
import { merge, lazyMerge } from "@formily/shared";
// Basic object merging
const target = { a: 1, b: { x: 10 } };
const source = { b: { y: 20 }, c: 3 };
const merged = merge(target, source);
// Result: { a: 1, b: { x: 10, y: 20 }, c: 3 }
// Array merging (default: concatenation)
const arr1 = { items: [1, 2] };
const arr2 = { items: [3, 4] };
const mergedArrays = merge(arr1, arr2);
// Result: { items: [1, 2, 3, 4] }
// Custom array merge strategy
const customMerged = merge(arr1, arr2, {
arrayMerge: (target, source) => source // Replace instead of concat
});
// Result: { items: [3, 4] }
// Assign mode (modify target in place)
const original = { a: 1 };
const result = merge(original, { b: 2 }, { assign: true });
// original is now { a: 1, b: 2 }
// result === original (same reference)
// Lazy merging with functions
const config1 = () => ({ database: { host: "localhost" } });
const config2 = () => ({ database: { port: 5432 } });
const lazyConfig = lazyMerge(config1, config2);
// Functions are called only when properties are accessed
console.log(lazyConfig.database.host); // "localhost"
console.log(lazyConfig.database.port); // 5432
// Lazy merging with objects
const defaults = { theme: "light", size: "medium" };
const userPrefs = () => ({ theme: "dark" });
const settings = lazyMerge(defaults, userPrefs);
console.log(settings.theme); // "dark" (from userPrefs function)
console.log(settings.size); // "medium" (from defaults object)import { merge } from "@formily/shared";
// Form configuration merging
const defaultFormConfig = {
validation: {
required: true,
minLength: 0
},
ui: {
placeholder: "Enter value",
disabled: false
}
};
const fieldConfig = {
validation: {
minLength: 5,
maxLength: 100
},
ui: {
disabled: true
}
};
const finalConfig = merge(defaultFormConfig, fieldConfig);
/*
Result: {
validation: {
required: true, // from default
minLength: 5, // from field (overrides default)
maxLength: 100 // from field (new)
},
ui: {
placeholder: "Enter value", // from default
disabled: true // from field (overrides default)
}
}
*/
// Custom merge function for specific keys
const config1 = { features: ["auth", "api"] };
const config2 = { features: ["ui", "db"] };
const customMerged = merge(config1, config2, {
customMerge: (key) => {
if (key === "features") {
return (target, source) => [...new Set([...target, ...source])]; // Union
}
return undefined; // Use default merge for other keys
}
});
// Result: { features: ["auth", "api", "ui", "db"] }
// Preventing cloning for performance
const largeObject = { /* large data structure */ };
const addition = { newField: "value" };
const efficientMerge = merge(largeObject, addition, {
clone: false // Don't clone existing properties
});The object operations in @formily/shared include special handling for various JavaScript objects and libraries:
$$typeof and _owner properties, handled safely to avoid circular references_isAMomentObject, handled appropriately for date operationstoJS method, converted to plain objects when cloning_isJSONSchemaObject, handled specially_isBigNumber, preserved during cloningtoJSON() method when available for serializationThis makes the utilities particularly well-suited for complex form applications that may use various JavaScript libraries and frameworks.