45 lines
1.1 KiB
TypeScript
45 lines
1.1 KiB
TypeScript
type PlainObject = Record<string, unknown>
|
|
|
|
export function deepMerge<T extends PlainObject>(baseValue: T, overrideValue: PlainObject): T {
|
|
if (!isPlainObject(baseValue)) {
|
|
return cloneValue(overrideValue) as T
|
|
}
|
|
|
|
const result = cloneValue(baseValue) as PlainObject
|
|
|
|
if (!isPlainObject(overrideValue)) {
|
|
return result as T
|
|
}
|
|
|
|
for (const [key, value] of Object.entries(overrideValue)) {
|
|
if (isPlainObject(value) && isPlainObject(result[key])) {
|
|
result[key] = deepMerge(result[key] as PlainObject, value)
|
|
continue
|
|
}
|
|
|
|
result[key] = cloneValue(value)
|
|
}
|
|
|
|
return result as T
|
|
}
|
|
|
|
function cloneValue<T>(value: T): T {
|
|
if (Array.isArray(value)) {
|
|
return value.map((item) => cloneValue(item)) as T
|
|
}
|
|
|
|
if (isPlainObject(value)) {
|
|
const output: PlainObject = {}
|
|
for (const [key, item] of Object.entries(value)) {
|
|
output[key] = cloneValue(item)
|
|
}
|
|
return output as T
|
|
}
|
|
|
|
return value
|
|
}
|
|
|
|
export function isPlainObject(value: unknown): value is PlainObject {
|
|
return Object.prototype.toString.call(value) === '[object Object]'
|
|
}
|