Skip to content

Instantly share code, notes, and snippets.

@fmartins-andre
Created February 6, 2025 16:52
Show Gist options
  • Save fmartins-andre/b414b374666e5af1f40366729a7eea68 to your computer and use it in GitHub Desktop.
Save fmartins-andre/b414b374666e5af1f40366729a7eea68 to your computer and use it in GitHub Desktop.
patchDeep: A function to deeply patch an object
declare type DeepPartial<T> = {
[K in keyof T]?: DeepPartial<T[K]> | undefined
}
const isObject = (obj: unknown) => obj && typeof obj === 'object'
/**
* Patch source object with other object.
* Only the source object keys are kept!
* Patch undefined values are ignored
*
* @param {TSource} source
* @param {TPatch} patch
* @return {*} {TSource}
*/
export function patchDeep<
TSource extends Record<string, unknown>,
TPatch extends DeepPartial<TSource>,
>(source: TSource, patch: TPatch): TSource {
if (!isObject(patch) || !isObject(source)) {
return source
}
const mergedObj = Object.entries(source).reduce(
(agg, [sourceKey, sourceValue]): TSource => {
const patchValue = patch[sourceKey]
if (Array.isArray(sourceValue)) {
return {
...agg,
[sourceKey]: Array.isArray(patchValue)
? patchValue.concat(sourceValue)
: sourceValue,
}
}
if (isObject(sourceValue)) {
return {
...agg,
[sourceKey]: isObject(patchValue)
? patchDeep(sourceValue as TSource, patchValue as TPatch)
: sourceValue,
}
}
return {
...agg,
[sourceKey]: patchValue === undefined ? sourceValue : patchValue,
}
},
Object.create({}) as TSource
)
return mergedObj
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment