Skip to content

Commit ae3696d

Browse files
authored
Merge pull request #122 from jsr-core/fix-test-equal
test[Equal]: fix false positive
2 parents 0981e0d + ad2042b commit ae3696d

File tree

2 files changed

+50
-1
lines changed

2 files changed

+50
-1
lines changed

_testutil.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { assertEquals } from "@std/assert";
2+
import type { IsExact } from "@std/testing/types";
23
import type { Predicate } from "./type.ts";
34

45
const examples = {
@@ -51,9 +52,14 @@ export async function testWithExamples<T>(
5152

5253
// It seems 'IsExact' in deno_std is false positive so use `Equal` in type-challenges
5354
// https://github.com/type-challenges/type-challenges/blob/e77262dba62e9254451f661cb4fe5517ffd1d933/utils/index.d.ts#L7-L9
54-
export type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends
55+
/** @deprecated use {@linkcode Equal} */
56+
export type TypeChallengesEqual<X, Y> = (<T>() => T extends X ? 1 : 2) extends
5557
(<T>() => T extends Y ? 1 : 2) ? true : false;
5658

59+
// `Equal` in type-challenges is false positive so combine `IsExact` + `Equal`.
60+
export type Equal<X, Y> = TypeChallengesEqual<X, Y> extends true ? IsExact<X, Y>
61+
: false;
62+
5763
export function stringify(x: unknown): string {
5864
if (x instanceof Date) return `Date(${x.valueOf()})`;
5965
if (x instanceof Promise) return "Promise";

_testutil_test.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// deno-lint-ignore-file no-explicit-any
2+
import { assertType, type IsExact } from "@std/testing/types";
3+
4+
import type { Equal, TypeChallengesEqual } from "./_testutil.ts";
5+
6+
declare class Foo<T> {
7+
declare private _: T;
8+
}
9+
10+
Deno.test("IsExact gives false positive", () => {
11+
// all of the following should be false
12+
assertType<IsExact<() => void, (x?: number) => void>>(true);
13+
assertType<IsExact<Foo<{ x: 1; a?: 1 }>, Foo<{ x: 1; b?: 1 }>>>(true);
14+
assertType<IsExact<() => any, () => number>>(true);
15+
assertType<IsExact<Foo<any>, Foo<number>>>(true);
16+
assertType<IsExact<{ a: 1 }, { readonly a: 1 }>>(true);
17+
});
18+
19+
Deno.test("TypeChallengesEqual gives false positive", () => {
20+
// all of the following should be false
21+
assertType<TypeChallengesEqual<[...any[]], [...any[], any]>>(true);
22+
assertType<TypeChallengesEqual<[any, ...any[]], [any, ...any[], any]>>(true);
23+
});
24+
25+
Deno.test("Equal", async (t) => {
26+
await t.step(
27+
"should be correct in cases where IsExact gives false positive",
28+
() => {
29+
assertType<Equal<() => void, (x?: number) => void>>(false);
30+
assertType<Equal<Foo<{ x: 1; a?: 1 }>, Foo<{ x: 1; b?: 1 }>>>(false);
31+
assertType<Equal<() => any, () => number>>(false);
32+
assertType<Equal<Foo<any>, Foo<number>>>(false);
33+
assertType<Equal<{ a: 1 }, { readonly a: 1 }>>(false);
34+
},
35+
);
36+
await t.step(
37+
"should be correct in cases where TypeChallengesEqual gives false positive",
38+
() => {
39+
assertType<Equal<[...any[]], [...any[], any]>>(false);
40+
assertType<Equal<[any, ...any[]], [any, ...any[], any]>>(false);
41+
},
42+
);
43+
});

0 commit comments

Comments
 (0)