export default function smartClone(obj: any, clonedObjects = new WeakMap()) : T { if (obj === null || typeof obj !== 'object') { return obj } if (clonedObjects.has(obj)) { return clonedObjects.get(obj) } const constructorMap: Map any> = new Map([ [Date, (obj: Date) => new Date(obj.getTime())], [RegExp, (obj: RegExp) => new RegExp(obj)], [Array, (obj: any[]) => obj.map((item) => smartClone(item, clonedObjects))], ] as Iterable<[DateConstructor | RegExpConstructor | ArrayConstructor, (obj: any) => any]>) const objConstructor = obj.constructor const cloneConstructor = constructorMap.get(objConstructor) if (cloneConstructor) { const clone = cloneConstructor(obj) clonedObjects.set(obj, clone) return clone } const proto = Object.getPrototypeOf(obj) const clone = Object.create(proto) clonedObjects.set(obj, clone) Object.keys(obj).forEach((key) => { if (Object.prototype.hasOwnProperty.call(obj, key)) { clone[key] = smartClone(obj[key], clonedObjects) } }) return clone }