Merge the properties of two class instances deeply

What is the best method for deep merging two instances of ES6 classes similar to lodash?
The end result should be an instance of the same class with a deep merge of both instances' properties.

Answer №1


If you do not need to instantiate a new object, simply use the code below:

_.merge(object1, object2)

With this code, the properties of object2 will be deeply merged into object1 while still keeping the prototype intact.


If you do need a completely new merged object, you can achieve it with the following code:

let newObject = Object.assign(Object.create(Object.getPrototypeOf(o1)), _.merge(o1, o2));

This code will create a fresh object that is an instance of the same class as o1, and it will perform a deep merge of the properties from both o1 and o2. However, be aware that there are some limitations to this approach, as mentioned in this source:

If the instance was constructed using closures extensively, it may be challenging to clone it accurately. It could be difficult to determine which internal values were set and how to replicate this setup.

Answer №2

My experience with Lodash merge was not successful when dealing with nested classes. Here's an example that demonstrates the issue:

class DeepEntity {
  @Exclude({ toPlainOnly: true })
  public id: string;
  public test: string;
}

class Entity {
  public id: string;
  public test: string;
  public deep: DeepEntity;
}

class DeepDto {
  public test: string;
}

class Dto {
  public test: string;
  public deep: DeepDto;
}

const entity = plainToInstance(Entity, {
  id: 'uuid',
  test: 'entity',
  deep: plainToInstance(DeepEntity, {
    id: 'deep-uuid',
    test: 'deep-entity',
  }),
});

const dto = plainToInstance(Dto, {
  id: 'uuid',
  test: 'dto',
  deep: plainToInstance(DeepDto, {
    id: 'deep-uuid',
    test: 'deep-dto',
  }),
});

const merged = merge(entity, dto);

// WNG: The following fails.
expect(merged.deep instanceof DeepEntity).toBe(true);

To resolve this issue, I found success in using mergeWith along with a customizer function like the one below:

import { instanceToPlain } from 'class-transformer';
import { isArray, isObjectLike, mergeWith } from 'lodash';

function customizer(objArray, srcArray, key) {
  // NOTE: Cast src to a plain object to prevent lodash from overriding prototypes.
  if (isObjectLike(srcArray) && !isArray(srcArray))
    return mergeWith(
      objArray,
      instanceToPlain(srcArray),
      customizer({ idCustomizers, defaultIdCustomizer }),
    );
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Clearing the ng-model value in a controller following an ng-change event

Is there a way to reset the ng-model value in the controller after an ngChange event without needing to use a directive? <div ng-repeat="i in items"> <!-- Some DOM comes here --> <select ng-model="i.avail" ng-change="changeAvail(i. ...

Creating designs on the canvas

With this code snippet, I have the ability to create lines using mouse points on a canvas. My goal is to identify when these lines connect to form a shape and then fill that shape with color. <script language="javascript" src="//ajax.googleapis.com/a ...

Deactivate a setInterval function within a Vue.js component

I am facing an issue in my VUE SPA where I have a component running a recursive countdown using setInterval functions. The problem is that the countdown continues running in the background even when I switch to another view, but I want to destroy the setIn ...

How can we bring in prop array values in React?

I've been working on developing a small music player program in React. Is there a way to import all these values together with a single import statement? I noticed that manually inputting the values into the props array doesn't work because the ...

*ngIf doesn't seem to be functioning as expected compared to other *ngIf directives

Encountering a peculiar issue with my *ngIf related to the isAdmin variable which determines whether the list of users in userList should be displayed or not. Strangely, it seems to behave differently compared to other *ngIf statements within the same comp ...

Toggle the visibility of multiple divs depending on a specific attribute value

I previously inquired about this issue, but I believe my wording was unclear and the responses focused on how to display or hide a group of divs when clicking a button. While I understand that concept, my specific challenge is slightly different. Let me pr ...

The retrieved information remains unchanged even after modifications are made on the subsequent Next.js server-side rendered page

I'm facing an interesting scenario with my application. It consists of two main pages - one displaying user account statistics and the other allowing users to edit these statistics. Both pages are rendered on the server side. When I navigate to the fi ...

Dropdown for state selection within WooCommerce for specific countries

I am encountering a challenge in configuring a form with default WooCommerce country and states selection dropdowns. Essentially, my goal is to present the Country selection first, followed by the State selection based on the chosen country. For instance, ...

Determining the best use-case for a React framework like Next or Gatsby versus opting for Create React App

As I delve into the world of React and JavaScript, I find myself in the fast-paced prototyping stage. I can't help but ponder at what point developers choose to utilize frameworks like Next.js or Gatsby.js over the usual Create React App. I'm pa ...

Connect this - initiate the removal of an item

I am seeking assistance from more experienced colleagues to help me understand the code below and implement it in my App. The main objective is to trigger a REDUX action from a button, which will delete an item from a database. Here is the code that curr ...

Retrieve the current element when the key is released and send it as a parameter to a different function

Imagine a scenario where my website contains textbox elements that are dynamically generated, each with the class 'mytxt'. <input type="text" class="mytxt" /> <input type="text" class="mytxt" /> <input type="text" class="mytxt" /& ...

I managed to pass an array of data to the client using EJS, but I encountered an issue trying to access the array on the client side after adding an index value

When I pass data received from an API to the client using EJS, I am struggling to access the JSON array on the client side. On the server side, I successfully send the returned data to the client like this: fetch(url) .then(res => res.json()) .the ...

Is it considered safe to modify variables by using this[varName] = something within a function that includes varName as a parameter?

As I continue working on this function, a question arises regarding the safety of changing variables in this manner. In my Angular service, I utilize utility functions where context represents this from the component calling the function. The code snippet ...

What are the best practices for utilizing AngularJS's $sanitize service?

Recently, I stumbled upon a tutorial discussing authentication in AngularJS. The tutorial showcased an AuthenticationService that was structured similarly to this: angular.module("auth").factory("AuthenticationService", function ($http, $sanitize) { ...

What sets Redux React-Native apart: Exploring the nuances between utilizing useSelector in react-redux versus connect

I believe they were identical because both extracted the content from the store. What could potentially differentiate them? ...

AutoComplete issues a warning in red when the value assigned to the useState hook it is associated with is altered

const [selectedCountry, setSelectedCountry] = useState(); <Autocomplete autoHighlight={true} //required autoSelect={true} id="geo-select-country" options={availableCountries} value={se ...

Browser now replacing attribute translate="yes" with translate="translate"

We have encountered an issue with a translation library that is affecting the functionality of our page. <html lang="en" class="notranslate translated-ltr"> <meta name="google" content="notranslate"> As ...

Center your attention on an AngularJS-created input element

I'm currently working on a todo list project using AngularJS and I am wondering if there is a method to automatically focus on an input box after creating it by clicking on a button. As of now, the save function in my controller looks like this: $sc ...

Exploring the capabilities of google-diff-match-patch within the Angular framework

Seeking a way to incorporate the google diff/match/patch lib into an Angular application for displaying the variance between two texts. Here's how I plan on using it: public ContentHtml: SafeHtml; compare(text1: string, text2: string):void { var ...

Streamline email error management within nested middleware functions

I have implemented an express route to handle password resets, which includes finding the user and performing some error handling. However, I am now faced with the challenge of adding additional error handling within a nested function, and I am uncertain a ...