Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deep cloning Entity instances in Typescript?

Attempting this:

/**
 * Deep clones an array of instances of type T and returns a new array.
 * @param array The array to deep clone
 * @return A new deep clone of the array argument
 *
 * @example
<pre>
  const original = [new Todo(), new Todo()];
  const result = [new Todo(), new Todo()];
  expect(deepClone(original)).to.eql(result);
</pre>
*/
export function deepClone<T extends Object>(array: T[]): T[] {
  return array.map((e:T) => ({...e}));
}

Typescript says:

[ts] Spread types may only be created from object types.

Should not T extends Object take care of this?

like image 419
Ole Avatar asked Oct 16 '22 12:10

Ole


2 Answers

If you duplicate an object with the spread operator, your new object won't be an instance of a class, but a literal object with no type, so it won't be a real clone of the existing object.

If the objects you want to clone are defined by you (not an external library) you could do something like:

export function deepClone(array: any[]): any[] {
  return array.map((e:any) => (new e.constructor(e)));
}

And then in your classes meant to be cloned:

constructor(obj: any) {
   Object.assign(this, obj);
}
like image 64
Guerric P Avatar answered Oct 20 '22 06:10

Guerric P


I use this method

https://stackblitz.com/edit/typescript-qmzgf7

const clone = obj =>
  Array.isArray(obj)
    ? obj.map(item => clone(item))
    : obj instanceof Date
      ? new Date(obj.getTime())
      : (typeof obj === 'object') && obj
        ? Object.getOwnPropertyNames(obj).reduce((o, prop) => ({ ...o, [prop]: clone(obj[prop]) }), {})
        : obj;

It doesn't work for all JavaScript object you might encounter, but it will likely work for anything that comes from a server call in JSON format.

like image 40
Adrian Brand Avatar answered Oct 20 '22 08:10

Adrian Brand