-
-
Save erikvullings/ada7af09925082cbb89f40ed962d475e to your computer and use it in GitHub Desktop.
/** | |
* Deep copy function for TypeScript. | |
* @param T Generic type of target/copied value. | |
* @param target Target value to be copied. | |
* @see Source project, ts-deepcopy https://github.com/ykdr2017/ts-deepcopy | |
* @see Code pen https://codepen.io/erikvullings/pen/ejyBYg | |
*/ | |
export const deepCopy = <T>(target: T): T => { | |
if (target === null) { | |
return target; | |
} | |
if (target instanceof Date) { | |
return new Date(target.getTime()) as any; | |
} | |
if (target instanceof Array) { | |
const cp = [] as any[]; | |
(target as any[]).forEach((v) => { cp.push(v); }); | |
return cp.map((n: any) => deepCopy<any>(n)) as any; | |
} | |
if (typeof target === 'object' && target !== {}) { | |
const cp = { ...(target as { [key: string]: any }) } as { [key: string]: any }; | |
Object.keys(cp).forEach(k => { | |
cp[k] = deepCopy<any>(cp[k]); | |
}); | |
return cp as T; | |
} | |
return target; | |
}; |
@MohammadFakhreddin Thanks for sharing your updates!
Thanks you for this :)
Thanks a lot @erikvullings
Hi there. Thanks for your code . I fixed a small issue inside it and I attached my final code. The part that you check that object is an instance of Array, there are some cases that we use libraries like RealmDb that they have defined their own array type and we need to clone that object to modify it. I changed that part to check for iterator instead and prevent it to be cloned as Object. Thanks again for your code.
export class ObjectHelper { /** * Deep copy function for TypeScript. * @param T Generic type of target/copied value. * @param target Target value to be copied. * @see Source project, ts-deeply https://github.com/ykdr2017/ts-deepcopy * @see Code pen https://codepen.io/erikvullings/pen/ejyBYg */ public static deepCopy<T>(target: T): T { if (target === null) { return target } if (target instanceof Date) { return new Date(target.getTime()) as any } // First part is for array and second part is for Realm.Collection // if (target instanceof Array || typeof (target as any).type === 'string') { if (typeof target === 'object') { if (typeof target[Symbol.iterator] === 'function') { const cp = [] as any[] if ((target as any as any[]).length > 0) { for (const arrayMember of target as any as any[]) { cp.push(ObjectHelper.deepCopy(arrayMember)) } } return cp as any as T } else { const targetKeys = Object.keys(target) const cp = {} if (targetKeys.length > 0) { for (const key of targetKeys) { cp[key] = ObjectHelper.deepCopy(target[key]) } } return cp as T } } // Means that object is atomic return target } }
how can i fix this ts error :
TS2538: Type 'symbol' cannot be used as an index type.
I guess its related to your typescript version because it works fine in Typescript "3.5.3". If you are not using something like realmdb original solution works fine. But for quick workaround you can trick your compiler in the following way:
(Symbol as any).iterator
I updated the posted code as well
Thank you so much!!!!
@MohammadFakhreddin
I'm sorry but your version doesn't seems to transpile even in TS 4+
This working with array, objects and persist datatype
function deepCopyObj<T>(obj: T): T { return JSON.parse(JSON.stringify(obj)) as T; }
I faced an issue when cloning object which had empty objects inside - the empty objects were only passed by reference and therefore any change to the new object affected the old one. I removed the 'target !== {}' to make it work for me. @erikvullings was there any other reason except from optimization for having the condition there?
This working with array, objects and persist datatype
function deepCopyObj<T>(obj: T): T { return JSON.parse(JSON.stringify(obj)) as T; }
True, but it is a rather expensive operation, and it will fail on circular objects, i.e. objects referring to itself.
I faced an issue when cloning object which had empty objects inside - the empty objects were only passed by reference and therefore any change to the new object affected the old one. I removed the 'target !== {}' to make it work for me. @erikvullings was there any other reason except from optimization for having the condition there?
No, not really - this copy/clone function is for basic usage only. I've also ported it to a more elaborate version that takes care of several other issues too, deep-copy-ts. Or you can get it from npm.
Hi there. Thanks for your code . I fixed a small issue inside it and I attached my final code. The part that you check that object is an instance of Array, there are some cases that we use libraries like RealmDb that they have defined their own array type and we need to clone that object to modify it. I changed that part to check for iterator instead and prevent it to be cloned as Object. Thanks again for your code.