deepClone()
deepClone<
T>(value):T
Creates a deep clone of a value, recursively cloning nested structures.
Handles primitives, arrays, Date, Map, Set, RegExp, Error, and plain objects. Preserves prototypes and symbol keys. Handles circular references. Functions are copied by reference (not cloned).
For TypedArrays, ArrayBuffer, Buffer, Blob, File, use deepCloneFull instead.
Type Parametersβ
T: Tβ
The type of the destination object.
Parametersβ
value: Tβ
The value to deep clone.
Returns: Tβ
A deep clone of the value.
Sinceβ
2.0.0
Performanceβ
O(n) time & space where n is total number of properties/elements.
Also known asβ
clone (Remeda, Ramda) Β· cloneDeep (Lodash, es-toolkit, Radashi) Β· β (Effect, Modern Dash, Antfu)
Examplesβ
const original = { a: 1, b: { c: 2 }, d: [3, 4] };
const cloned = deepClone(original);
cloned.b.c = 99;
original.b.c; // => 2 (unchanged)
const circular: `Record<string, unknown>` = { a: 1 };
circular.self = circular;
const cloned = deepClone(circular);
cloned.self === cloned; // => true
How it works?β
Creates a deep copy of a value, recursively cloning all nested structures.
Independenceβ
Circular Reference Handlingβ
Use Casesβ
Duplicate simple state πβ
Create a deep copy of an object to avoid mutation bugs. Essential for Redux-style state updates or immutable patterns.
const newState = deepClone(currentState);
newState.user.isActive = true; // Safe mutation
Snapshot state historyβ
Store copies of state at specific points in time for undo/redo functionality.
const history = [];
function pushState(state) {
history.push(deepClone(state));
}
Break referencesβ
Ensure that nested objects are fully decoupled from the original. Useful when passing data to components that might mutate it.
const original = { config: { retries: 3 } };
const copy = deepClone(original);
copy.config.retries = 5;
console.log(original.config.retries); // 3
Clone form state for reset and dirty-checkingβ
Store the initial form state to enable "Reset" and detect unsaved changes. Universal pattern for form-heavy applications with save/discard workflows.
const initialValues = deepClone(formData);
// User edits the form...
formData.name = "Updated Name";
formData.address.city = "New City";
// Dirty check: compare current state with original
const hasChanges = JSON.stringify(formData) !== JSON.stringify(initialValues);
// => true
// Reset: restore original values
function resetForm() {
Object.assign(formData, deepClone(initialValues));
}
Save game state checkpointsβ
Store deep copies of game state at key moments for save/load functionality. Essential for games with save points, level transitions, or undo mechanics.
const saveCheckpoint = (gameState: GameState) => {
const checkpoint = deepClone(gameState);
checkpoints.push({
state: checkpoint,
timestamp: Date.now(),
level: gameState.currentLevel,
});
};
// Player reaches a save point
saveCheckpoint(currentGameState);
// Load last checkpoint after game over
const lastSave = checkpoints[checkpoints.length - 1];
currentGameState = deepClone(lastSave.state);
Clone overlay configuration before openingβ
Deep clone overlay options before passing to the overlay service to prevent shared state. Essential for overlay/dialog systems where multiple instances share a base config.
const baseDialogConfig = {
width: "400px",
hasBackdrop: true,
position: { top: "100px" },
panelClass: "default-dialog",
data: { title: "", content: "" },
};
const openDialog = (overrides: Partial<typeof baseDialogConfig>) => {
const config = deepClone(baseDialogConfig);
Object.assign(config, overrides);
Object.assign(config.data, overrides.data);
return overlayService.open(config);
};
// Each dialog gets its own config, no shared mutation
openDialog({ data: { title: "Confirm", content: "Are you sure?" } });
openDialog({ data: { title: "Delete", content: "This is permanent." } });
Snapshot tree expand/collapse state for undoβ
Clone the tree expansion state before a bulk operation to enable undo. Essential for tree components with "Expand All" / "Collapse All" actions.
const treeState = {
"root": { expanded: true },
"root/src": { expanded: true },
"root/src/components": { expanded: false },
"root/tests": { expanded: false },
};
let previousState = deepClone(treeState);
const expandAll = () => {
previousState = deepClone(treeState);
Object.values(treeState).forEach((node) => { node.expanded = true; });
renderTree(treeState);
};
const undoExpand = () => {
Object.assign(treeState, deepClone(previousState));
renderTree(treeState);
};
Clone cached API response before mutationβ
Deep clone cached data before modifying it to keep the cache intact. Critical for apps with client-side caching where components may mutate data.
const getCachedUsers = () => {
const cached = cache.get("users");
if (!cached) return null;
// Clone so mutations don't corrupt the cache
return deepClone(cached);
};
const users = getCachedUsers();
users[0].name = "Modified"; // Safe: cache is untouched