50 lines
1.5 KiB
TypeScript
50 lines
1.5 KiB
TypeScript
const deepCloneFallback = <T>(value: T, cache = new WeakMap()): T => {
|
|
if (value === null || typeof value !== "object") return value
|
|
if (cache.has(value as object)) return cache.get(value as object)
|
|
|
|
if (value instanceof Date) return new Date(value.getTime()) as T
|
|
if (value instanceof Map) {
|
|
const clonedMap = new Map()
|
|
cache.set(value as object, clonedMap)
|
|
value.forEach((mapValue, mapKey) => {
|
|
clonedMap.set(
|
|
deepCloneFallback(mapKey, cache),
|
|
deepCloneFallback(mapValue, cache)
|
|
)
|
|
})
|
|
return clonedMap as T
|
|
}
|
|
if (value instanceof Set) {
|
|
const clonedSet = new Set()
|
|
cache.set(value as object, clonedSet)
|
|
value.forEach((setValue) => {
|
|
clonedSet.add(deepCloneFallback(setValue, cache))
|
|
})
|
|
return clonedSet as T
|
|
}
|
|
if (Array.isArray(value)) {
|
|
const clonedArr: any[] = []
|
|
cache.set(value as object, clonedArr)
|
|
value.forEach((item, index) => {
|
|
clonedArr[index] = deepCloneFallback(item, cache)
|
|
})
|
|
return clonedArr as T
|
|
}
|
|
|
|
const clonedObj: Record<string, any> = {}
|
|
cache.set(value as object, clonedObj)
|
|
Object.keys(value as object).forEach((key) => {
|
|
clonedObj[key] = deepCloneFallback((value as any)[key], cache)
|
|
})
|
|
return clonedObj as T
|
|
}
|
|
|
|
export const safeClone = <T>(value: T): T => {
|
|
try {
|
|
return structuredClone(value)
|
|
} catch (error) {
|
|
console.warn("structuredClone failed, fallback to deep clone", error)
|
|
return deepCloneFallback(value)
|
|
}
|
|
}
|