Skip to content

Commit 277255b

Browse files
committed
fix(merge, mergeWith): Handle top-level type mismatch consistently
1 parent e220bb7 commit 277255b

File tree

4 files changed

+36
-0
lines changed

4 files changed

+36
-0
lines changed

src/object/merge.spec.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,4 +118,12 @@ describe('merge', () => {
118118
expect(result).toEqual({ a: 2 });
119119
expect(result.__proto__).toBe(Object.prototype);
120120
});
121+
122+
it('should handle top-level type mismatch consistently with nested behavior', () => {
123+
const topLevelResult = merge(['1'] as any, { a: 2 });
124+
const nestedResult = merge({ x: ['1'] }, { x: { a: 2 } } as any);
125+
126+
expect(topLevelResult).toEqual({ a: 2 });
127+
expect(nestedResult.x).toEqual({ a: 2 });
128+
});
121129
});

src/object/merge.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,16 @@ export function merge<T extends Record<PropertyKey, any>, S extends Record<Prope
4545
target: T,
4646
source: S
4747
): T & S {
48+
if (Array.isArray(source)) {
49+
if (!Array.isArray(target)) {
50+
return merge([] as unknown as T, source);
51+
}
52+
} else if (isPlainObject(source)) {
53+
if (!isPlainObject(target)) {
54+
return merge({} as unknown as T, source);
55+
}
56+
}
57+
4858
const sourceKeys = Object.keys(source) as Array<keyof S>;
4959

5060
for (let i = 0; i < sourceKeys.length; i++) {

src/object/mergeWith.spec.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,12 @@ describe('mergeWith', () => {
125125

126126
expect(result).toEqual({ a: { b: { x: 1 }, c: { y: 2 }, d: { z: 3 } } });
127127
});
128+
129+
it('should handle top-level type mismatch consistently with nested behavior', () => {
130+
const topLevelResult = mergeWith(['1'] as any, { a: 2 }, () => undefined);
131+
const nestedResult = mergeWith({ x: ['1'] }, { x: { a: 2 } } as any, () => undefined);
132+
133+
expect(topLevelResult).toEqual({ a: 2 });
134+
expect(nestedResult.x).toEqual({ a: 2 });
135+
});
128136
});

src/object/mergeWith.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,16 @@ export function mergeWith<T extends Record<PropertyKey, any>, S extends Record<P
5454
source: S,
5555
merge: (targetValue: any, sourceValue: any, key: string, target: T, source: S) => any
5656
): T & S {
57+
if (Array.isArray(source)) {
58+
if (!Array.isArray(target)) {
59+
return mergeWith([] as unknown as T, source, merge);
60+
}
61+
} else if (isPlainObject(source)) {
62+
if (!isPlainObject(target)) {
63+
return mergeWith({} as unknown as T, source, merge);
64+
}
65+
}
66+
5767
const sourceKeys = Object.keys(source) as Array<keyof T>;
5868

5969
for (let i = 0; i < sourceKeys.length; i++) {

0 commit comments

Comments
 (0)