diff --git a/src/compat/predicate/isMatch.spec.ts b/src/compat/predicate/isMatch.spec.ts index 3536e962d..3e7572a39 100644 --- a/src/compat/predicate/isMatch.spec.ts +++ b/src/compat/predicate/isMatch.spec.ts @@ -33,6 +33,10 @@ describe('isMatch', () => { expect(isMatch({ a: { b: { c: 1, d: 2 }, e: 3 }, f: 4 }, { a: { b: { c: 1 } } })).toBe(true); }); + it('should return `false` when nested source primitive does not match object target', () => { + expect(isMatch({ a: { b: 2 } }, { a: 1 })).toBe(false); + }); + it(`should match boolean values`, () => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error diff --git a/src/compat/predicate/isMatchWith.spec.ts b/src/compat/predicate/isMatchWith.spec.ts index d2dfce281..23f49d4e3 100644 --- a/src/compat/predicate/isMatchWith.spec.ts +++ b/src/compat/predicate/isMatchWith.spec.ts @@ -338,6 +338,10 @@ describe('isMatchWith', () => { expect(isMatchWith({}, {}, rootCustomizer)).toBe(true); }); + it('should return `false` when nested source primitive does not match object target', () => { + expect(isMatchWith({ a: { b: 2 } }, { a: 1 }, () => undefined)).toBe(false); + }); + it('should handle empty collections', () => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error diff --git a/src/compat/predicate/isMatchWith.ts b/src/compat/predicate/isMatchWith.ts index 5acece7f9..76153c4ca 100644 --- a/src/compat/predicate/isMatchWith.ts +++ b/src/compat/predicate/isMatchWith.ts @@ -124,9 +124,10 @@ export function isMatchWith( return Boolean(isEqual); } - return isMatchWithInternal(objValue, srcValue, doesMatch, stack); + return isMatchWithInternal(objValue, srcValue, doesMatch, stack, false); }, - new Map() + new Map(), + true ); } @@ -141,7 +142,8 @@ function isMatchWithInternal( source: any, stack?: Map ) => boolean | undefined, - stack?: Map + stack?: Map, + isRoot = false ): boolean { if (source === target) { return true; @@ -155,7 +157,7 @@ function isMatchWithInternal( const sourceKeys = Object.keys(source); if (sourceKeys.length > 0) { - return isMatchWithInternal(target, { ...source }, compare, stack); + return isMatchWithInternal(target, { ...source }, compare, stack, isRoot); } return eq(target, source); @@ -165,11 +167,15 @@ function isMatchWithInternal( return eq(target, source); } - if (typeof source === 'string') { - return source === ''; + if (isRoot) { + if (typeof source === 'string') { + return source === ''; + } + + return true; } - return true; + return eq(target, source); } } } diff --git a/src/compat/predicate/matches.spec.ts b/src/compat/predicate/matches.spec.ts index cbaf49536..aa86bb0f6 100644 --- a/src/compat/predicate/matches.spec.ts +++ b/src/compat/predicate/matches.spec.ts @@ -25,6 +25,10 @@ describe('matches', () => { expect(isMatch5({ a: { b: { c: 1, d: 2 }, e: 3 }, f: 4 })).toBe(true); }); + it('should return `false` when nested source primitive does not match object target', () => { + expect(matches({ a: 1 })({ a: { b: 2 } })).toBe(false); + }); + it(`should match inherited string keyed \`object\` properties`, () => { interface Foo { a: number;