Last active
October 10, 2022 14:21
-
-
Save AyAyEm/53def5b7abfd5cfbfc3674284ec6b26f to your computer and use it in GitHub Desktop.
A functional approach to merging objects
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export type Obj = Record<string | number | symbol, unknown>; | |
export function mergeObjects<A extends Obj, B extends Obj>(a: A, b: B): A & B { | |
if (Array.isArray(a) && Array.isArray(b)) { | |
return [...a, ...b] as unknown as A & B; | |
} else if (Array.isArray(b)) { | |
return b as unknown as A & B; | |
} | |
const mappedEntries = [...Object.keys(a), ...Object.keys(b)].map((key) => { | |
const value = { | |
a: a[key], | |
b: b[key], | |
} as const; | |
if (!containsKey(key, a)) { | |
return [key, value.b]; | |
} else if (!containsKey(key, b)) { | |
return [key, value.a]; | |
} | |
if (isObject(value.a) && isObject(value.b)) { | |
return [key, mergeObjects(value.a, value.b)]; | |
} | |
return [key, value.b]; | |
}); | |
return Object.fromEntries(mappedEntries); | |
} | |
function containsKey( | |
key: string | number | symbol, | |
obj: { key: unknown } | |
): true; | |
// I don't know how to make this typing work as expected | |
function containsKey<K extends string | number | symbol>( | |
key: K, | |
obj: Obj | |
): obj is { [Key in K]: typeof obj[Key] }; | |
function containsKey(key: string | number | symbol, obj: Obj): boolean { | |
return !isUndefined(obj[key]); | |
} | |
export function isUndefined(value: undefined): true; | |
export function isUndefined(value: unknown): value is undefined; | |
export function isUndefined(value: unknown): boolean { | |
return typeof value === 'undefined'; | |
} | |
export function isNull(value: null): true; | |
export function isNull(value: unknown): value is null; | |
export function isNull(value: unknown): boolean { | |
return value === null; | |
} | |
export function isObject(value: undefined): true; | |
export function isObject(value: unknown | undefined): value is Obj; | |
export function isObject(value: unknown): boolean { | |
return !isUndefined(value) && !isNull(value) && typeof value === 'object'; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment