Skip to content

Commit

Permalink
fix(isDeepEqual): Prevent redundant narrowing (#635)
Browse files Browse the repository at this point in the history
Fixes: #634

Narrowing the result of isDeepEqual is redundant when the type isn't
effectively narrowed because it breaks the rejected/negated path which
would be `never`.

This means that the common use case where both objects are of the same
type and narrowing was meaningless, will now act as a regular boolean
check.
  • Loading branch information
eranhirsch committed Apr 13, 2024
1 parent c0e9213 commit 8e18bec
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 3 deletions.
27 changes: 27 additions & 0 deletions src/isDeepEqual.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,17 +257,23 @@ describe("typing", () => {

if (isDeepEqual(data, 1)) {
expectTypeOf(data).toEqualTypeOf<number>();
} else {
expectTypeOf(data).toEqualTypeOf<number | string>();
}

if (isDeepEqual(data, "hello")) {
expectTypeOf(data).toEqualTypeOf<string>();
} else {
expectTypeOf(data).toEqualTypeOf<number | string>();
}
});

it("narrows to literal", () => {
const data = 1 as number;
if (isDeepEqual(data, 1 as const)) {
expectTypeOf(data).toEqualTypeOf<1>();
} else {
expectTypeOf(data).toEqualTypeOf<number>();
}
});

Expand All @@ -282,6 +288,27 @@ describe("typing", () => {
>;
if (isDeepEqual(data, [{ a: [1] }])) {
expectTypeOf(data).toEqualTypeOf<Array<{ a: Array<number> }>>();
} else {
expectTypeOf(data).toEqualTypeOf<
Array<
| {
a: Array<number> | Array<string>;
}
| {
b: Array<boolean>;
}
>
>();
}
});

it("doesn't narrow when comparing objects of the same type", () => {
const data1 = { a: 1 } as { a: number };
const data2 = { a: 2 } as { a: number };
if (isDeepEqual(data1, data2)) {
expectTypeOf(data1).toEqualTypeOf<{ a: number }>();
} else {
expectTypeOf(data1).toEqualTypeOf<{ a: number }>();
}
});
});
11 changes: 8 additions & 3 deletions src/isDeepEqual.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ import { purry } from "./purry";
* @dataFirst
* @category Guard
*/
export function isDeepEqual<T, S extends T = T>(data: T, other: S): data is S;
export function isDeepEqual<T, S extends T>(
data: T,
other: T extends Exclude<T, S> ? S : never,
): data is S;
export function isDeepEqual<T, S extends T = T>(data: T, other: S): boolean;

/**
* Performs a deep *semantic* comparison between two values to determine if they
Expand All @@ -51,9 +55,10 @@ export function isDeepEqual<T, S extends T = T>(data: T, other: S): data is S;
* @dataLast
* @category Guard
*/
export function isDeepEqual<T, S extends T>(other: S): (data: T) => data is S;
export function isDeepEqual<T, S extends T = T>(
other: S,
): (data: T) => data is S;
other: T extends Exclude<T, S> ? S : never,
): (data: T) => boolean;

export function isDeepEqual(): unknown {
return purry(isDeepEqualImplementation, arguments);
Expand Down

0 comments on commit 8e18bec

Please sign in to comment.