I know this is a bit of an old issue but the easiest solution in ES2015/ES6 I could come up with was actually quite simple, using Object.assign(),

Hopefully this helps:

/**
 * Simple object check.
 * @param item
 * @returns {boolean}
 */
export function isObject(item) {
  return (item && typeof item === 'object' && !Array.isArray(item));
}

/**
 * Deep merge two objects.
 * @param target
 * @param ...sources
 */
export function mergeDeep(target, ...sources) {
  if (!sources.length) return target;
  const source = sources.shift();

  if (isObject(target) && isObject(source)) {
    for (const key in source) {
      if (isObject(source[key])) {
        if (!target[key]) Object.assign(target, { [key]: {} });
        mergeDeep(target[key], source[key]);
      } else {
        Object.assign(target, { [key]: source[key] });
      }
    }
  }

  return mergeDeep(target, ...sources);
}

Example usage:

mergeDeep(this, { a: { b: { c: 123 } } });
// or
const merged = mergeDeep({a: 1}, { b : { c: { d: { e: 12345}}}});  
console.dir(merged); // { a: 1, b: { c: { d: [Object] } } }

You'll find an immutable version of this in the answer below.

Note that this will lead to infinite recursion on circular references. There's some great answers on here on how to detect circular references if you think you'd face this issue.

Answer from Salakar on Stack Overflow
Top answer
1 of 15
317

I know this is a bit of an old issue but the easiest solution in ES2015/ES6 I could come up with was actually quite simple, using Object.assign(),

Hopefully this helps:

/**
 * Simple object check.
 * @param item
 * @returns {boolean}
 */
export function isObject(item) {
  return (item && typeof item === 'object' && !Array.isArray(item));
}

/**
 * Deep merge two objects.
 * @param target
 * @param ...sources
 */
export function mergeDeep(target, ...sources) {
  if (!sources.length) return target;
  const source = sources.shift();

  if (isObject(target) && isObject(source)) {
    for (const key in source) {
      if (isObject(source[key])) {
        if (!target[key]) Object.assign(target, { [key]: {} });
        mergeDeep(target[key], source[key]);
      } else {
        Object.assign(target, { [key]: source[key] });
      }
    }
  }

  return mergeDeep(target, ...sources);
}

Example usage:

mergeDeep(this, { a: { b: { c: 123 } } });
// or
const merged = mergeDeep({a: 1}, { b : { c: { d: { e: 12345}}}});  
console.dir(merged); // { a: 1, b: { c: { d: [Object] } } }

You'll find an immutable version of this in the answer below.

Note that this will lead to infinite recursion on circular references. There's some great answers on here on how to detect circular references if you think you'd face this issue.

2 of 15
253

You can use Lodash merge:

var object = {
  'a': [{ 'b': 2 }, { 'd': 4 }]
};

var other = {
  'a': [{ 'c': 3 }, { 'e': 5 }]
};

console.log(_.merge(object, other));
// => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>

🌐
GeeksforGeeks
geeksforgeeks.org › typescript › how-to-deep-merge-two-objects-in-typescript
How to Deep Merge Two Objects in TypeScript ? - GeeksforGeeks
June 16, 2025 - In this example, we have two objects obj1 and obj2 with nested properties. We use a recursive function deepMerge to merge these objects deeply.
Discussions

How to specify nested types? When objects are merged together
// if all keys are required type PomsTranslations = DimensionsTranslations & QuestionsTranslations & EmotionsTranslations; // if all keys are optional type PomsTranslations = Partial; More on reddit.com
🌐 r/typescript
2
3
May 29, 2024
Is there a benefit to using lodash.merge (or other utilities of the same feature) versus merging via object destructuring?
Yes, absolutely. Lodash merge recursively merges properties at every level. If you merged two objects with destructuring (or lodash.assign or Object.assign which are equivalent), it drops anything that is not top-level from the first object. See: https://lodash.com/docs#merge More on reddit.com
🌐 r/node
13
4
November 14, 2022
Typescript says object is possibly 'undefined' for an object property, even after checking/narrowing if the property exists.
Try first assigning person[type] to a variable, then do the condition and the find on that variable. That should work. I remember reading a while back that typescript does this for safety because it cannot statically determine the difference between a getter and a property so what is truthy on one line may no longer be on the next if it's a getter. More on reddit.com
🌐 r/typescript
11
8
February 10, 2022
Javascript Object Merge
This merge will have some problems. You're better off sticking to a more battle-tested merge such as lodash's merge . More on reddit.com
🌐 r/learnjavascript
28
183
February 16, 2021
🌐
Sandtoken
sandtoken.com › writing › typescript-deep-merge-explained
Deep Merge in TypeScript - A Type-Safe Approach to Object Combination
October 19, 2024 - The deep merge utility provides a robust, type-safe solution for combining nested objects in TypeScript applications.
🌐
DEV Community
dev.to › svehla › typescript-how-to-deep-merge-170c
How to deep merge in Typescript - DEV Community
October 5, 2021 - This generic checks that both parameters are of type { [key: string]: unknown } (aka Object). If it’s true it merges them via MergeTwoObject<>. This process is recursively repeated for all nested objects.
🌐
Squash
squash.io › tutorial-on-merging-objects-in-typescript
How to Merge Objects in TypeScript - Squash Labs
May 8, 2024 - This can be achieved using the spread operator or the Object.assign method. Here's an example of merging nested objects using the spread operator:
🌐
Medium
medium.com › developersglobal › mastering-typescript-deep-object-spreading-a-complete-guide-to-merging-nested-objects-aec334b39c50
Mastering TypeScript Deep Object Spreading: A Complete Guide to Merging Nested Objects | by Abhishek kumaar | DevelopersGlobal | Medium
April 4, 2025 - Shallow object spreading copies only the top-level properties, and nested objects remain referenced. const obj1 = { name: "Amit", address: { city: "Delhi", country: "India" } }; const obj2 = { age: 30 }; const merged = { ...obj1, ...obj2 }; console.log(merged); // Output: { name: "Amit", address: { city: "Delhi", country: "India" }, age: 30 }
🌐
Amitd
amitd.co › code › typescript › recursively-deep-merging-objects
Recursively deep merging objects — Typescript — Amit Dhamu — Staff Engineer
type Props = Record<string, any> const deepMerge = (target: Props, ...sources: Props[]): Props => { if (!sources.length) { return target } Object.entries(sources.shift() ?? []).forEach(([key, value]) => { if (value) { if (!target[key]) { Object.assign(target, { [key]: {} }) } if ( value.constructor === Object || (value.constructor === Array && value.find(v => v.constructor === Object)) ) { deepMerge(target[key], value) } else if (value.constructor === Array) { Object.assign(target, { [key]: value.find(v => v.constructor === Array) ? target[key].concat(value) : [...new Set([...target[key], ...value])], }) } else { Object.assign(target, { [key]: value }) } } }) return target } Shallow merge · Identical properties stay the same · Flat arrays are joined with duplicates removed · Nested arrays are joined together ·
🌐
GitHub
github.com › mesqueeb › merge-anything
GitHub - mesqueeb/merge-anything: Merge objects & other types recursively. A simple & small integration. · GitHub
merge-anything will merge objects and nested properties, but only as long as they're "plain objects". As soon as a sub-prop is not a "plain object" and has a special prototype, it will copy that instance over "as is".
Author: mesqueeb
Find elsewhere
🌐
npm
npmjs.com › package › ts-deepmerge
ts-deepmerge - npm
May 22, 2026 - A deep merge function that automatically infers the return type based on your input, without mutating the source objects.
      » npm install ts-deepmerge
    
Published: May 22, 2026
Version: 8.0.0
🌐
Python Guides
pythonguides.com › merge-objects-in-typescript
Merge Objects In TypeScript
July 9, 2025 - In this tutorial, we learned how to merge objects in TypeScript using the spread operator, Object.assign(), and deep merge functions. For the nested structures, we explored how to perform deep merges using a custom recursive function.
🌐
npm
npmjs.com › package › merge-anything
merge-anything - npm
March 24, 2025 - merge-anything will merge objects and nested properties, but only as long as they're "plain objects". As soon as a sub-prop is not a "plain object" and has a special prototype, it will copy that instance over "as is".
      » npm install merge-anything
    
Published: Sep 28, 2026
Version: 6.0.8
🌐
Es-toolkit
es-toolkit.dev › reference › object › merge.html
merge | es-toolkit
typescript · const result = merge(target, source); Use merge when you want to deeply merge two objects. Nested objects and arrays are also merged recursively. Unlike toMerged, this function modifies the original target object. typescript ·
🌐
GitHub
gist.github.com › ahtcx › 0cd94e62691f539160b32ecda18af3d6
Deep-Merge JavaScript objects with ES6 · GitHub
With the improvements relying on iterating with key/values using for (const [k,v] of Object.entries(...)), and constructing "whatever this object was if it's missing in the target" based on the __proto__ constructor. (and with swapped args because you look for needles in haystacks, and you merge sources into targets) ... @Pomax This ^^ is the best solution to date and solves some multi-level nested object issues with the original gist.
🌐
SPGuides
spguides.com › merge-two-objects-in-typescript
How to Merge Two Objects in TypeScript?
February 7, 2024 - Remember that both the spread syntax and Object.assign() perform shallow merges. This means that if the objects contain nested objects, those nested objects will not be deeply merged but rather replaced or copied over. Merging all objects in an array into a single object is a common task in TypeScript development.
🌐
npm
npmjs.com › package › object-deep-merge
object-deep-merge - npm
October 20, 2025 - Latest version: 2.0.1, last published: 13 hours ago. Start using object-deep-merge in your project by running `npm i object-deep-merge`. There are 5 other projects in the npm registry ...
      » npm install object-deep-merge
    
Published: May 19, 2026
Version: 2.0.1
🌐
Webdevtutor
webdevtutor.net › blog › typescript-merge-two-objects-recursively
How to Merge Two Objects Recursively in TypeScript
By using a recursive function like the one shown above, you can easily merge two objects recursively in TypeScript. This approach allows you to combine nested properties efficiently and maintain the structure of the original objects.
🌐
Medium
medium.com › @srajas02 › merge-two-objects-deeply-nested-in-javascript-8e8515b4f8d3
Merge two objects deeply nested in Javascript | by RAJA S | Medium
November 18, 2022 - In this blog, you will learn how two objects can be merged deeply nested objects. Javascript is offering Object.assign() and Spread Operator to merge the objects.
🌐
Sling Academy
slingacademy.com › home › typescript › how to merge multiple objects in typescript (2 approaches)
How to Merge Multiple Objects in TypeScript (2 Approaches) - Sling Academy
December 3, 2023 - const objectOne = { name: 'Product One', price: 100, description: 'This is product one', }; const objectTwo = { weight: 100, color: 'red', }; const objectThree = { name: 'Product Three', descriptioN: 'Some text', color: 'blue', }; // Merge objectOne and objectTwo by using Object.assign() const resultOne = Object.assign({}, objectOne, objectTwo); console.log(resultOne); // Merge objectOne, objectTwo, and objectThree by using Object.assign() const resultTwo = Object.assign({}, objectOne, objectTwo, objectThree); console.log(resultTwo); ... // console.log(resultOne); { name: 'Product One', price:
🌐
SitePoint
sitepoint.com › blog › javascript › how to merge objects in javascript
How to Merge Objects in JavaScript — SitePoint
November 5, 2024 - Both the spread operator and Object.assign() create a shallow copy of the object(s) being copied. Essentially this means the new object will have references to the same nested objects (e.g. arrays and functions) as the original object, rather than having copies of them. Knowing and avoiding this is essential before merging objects together.