Reputation: 12133
How do I properly deep merge (lodash
like) two ES6 class instances?
The resulting object has to be an actual instance of the same class and its properties should be a deep merge of the two instances' properties.
Upvotes: 2
Views: 1443
Reputation: 21
Lodash merge did not work for me as is for nested classes. See this test:
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);
What worked for me was to use mergeWith
with a customizer like this one:
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 }),
);
}
Upvotes: 0
Reputation: 12133
If there is no need to create a new instance, the following will do
_.merge(instance1, instance2)
This will deep merge instance2
properties into instance1
while preserving the prototype.
If the merged instance should be a brand new object it is still achievable:
let newInstance = Object.assign(Object.create(Object.getPrototypeOf(o1)), _.merge(o1, o2));
This will create a new object which is an instance of the same class o1
is and will deep merge into it the properties of o1
and o2
.
This approach, however, has some caveats, for example (from here):
It's hardly possible if the instance was created with heavy use of closures in the constructor function. We may never now which internal values were set, and how to reproduce such a setup.
Upvotes: 1