-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclone.ts
88 lines (66 loc) · 2.21 KB
/
clone.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import type { UnknownArray, UnknownObject, Writable } from '@13onthecode/types'
import { isArray } from '../guard/isArray'
import { isArrayBuffer } from '../guard/isArrayBuffer'
import { isDataView } from '../guard/isDataView'
import { isDate } from '../guard/isDate'
import { isMap } from '../guard/isMap'
import { isObject } from '../guard/isObject'
import { isRegExp } from '../guard/isRegExp'
import { isSet } from '../guard/isSet'
import { isSymbol } from '../guard/isSymbol'
import { isTypedArray } from '../guard/isTypedArray'
export type CloneOptions = {
mode?: 'deep' | 'shallow'
}
export function clone<T>(
source: T,
options?: CloneOptions
): T {
let result = source as unknown
const isDeep = options?.mode === 'deep'
if (isArrayBuffer(source)) {
result = new ArrayBuffer(source.byteLength)
}
if (isDataView(source) || isTypedArray(source)) {
const { buffer, byteLength, byteOffset, constructor } = source
result = new (constructor as new (...args: unknown[]) => T)(isDeep ? clone(buffer, options) : buffer, byteOffset, byteLength)
}
if (isDate(source)) {
result = new Date(source)
}
if (isRegExp(source)) {
result = new RegExp(source)
}
if (isSymbol(source)) {
result = Symbol(source.description)
}
if (isSet(source)) {
const clonedSet = new Set()
for (const item of source) {
clonedSet.add(item === source ? clonedSet : (isDeep ? clone(item, options) : item))
}
result = clonedSet
}
if (isMap(source)) {
const clonedMap = new Map()
for (const [key, value] of source) {
clonedMap.set(key, value === source ? clonedMap : (isDeep ? clone(value, options) : value))
}
result = clonedMap
}
if (isArray(source)) {
const clonedArray: Writable<UnknownArray> = []
for (const item of source) {
clonedArray.push(item === source ? clonedArray : (isDeep ? clone(item, options) : item))
}
result = clonedArray
}
if (isObject(source)) {
const clonedObject: Writable<UnknownObject> = {}
for (const [key, value] of Object.entries(source)) {
clonedObject[key] = value === source ? clonedObject : (isDeep ? clone(value, options) : value)
}
result = clonedObject
}
return result as T
}