Repository: sindresorhus/type-fest (TypeScript)

Issue:
`IsEqual` identity issues
There are two self-identity bugs that can pretty simply be fixed: [TS Playground](https://www.typescriptlang.org/play?#code/PQgEGUAsHsHcGMCGBnAps0qBOXpY7JKgHagCuxAltFcQOah6iXEAu2a8rLDrRoyRAFtUoVgE8ADqgCwAKHkBveaDFTRASWQBRAI5lEAGwA8AQQA0oAEIA+UAF4Vq0AApjAcRsuAlA7vvMAA92YgATDFNQAH5QAEZQAC5QACZfVGCScKdVN08fP1AA9JDw62i4xJTvbPLWLDJZOWdKgDMjNABueSdFNWlMfXaHUC09AxNexCT4gF9QAB9QSenQGctlipm7GacwZoA9KO6mpb7RVEHDDHsRnUvjDdnQADJTqc310HfZ7d3gZtAh3kOwUcjAADFKIExPxFkg0EonBJ+qN7hZrHZHCcch4vL57P4giUIgtCuV4klUkTMsgark8QUihkwhgrKSAjEKVUajE6g0akk2ldUF1QapesjzpdrrcxkYHl8VnNFo9Vp9vqtfic9s4gWLTpKBuMZajxgqNXNXqq1m8lVrVDrVHqQfIIVCYaJXvDGsoTobTfL0bYHHTcfkCWTijTQJFXhyKpS0systjXGH8YSoyyynHyZVUjyxPVGs1Be0RcdxWcjUMbgGJorNqTreq7as-gC9T1qxdjcN6+alS9bR8Rz929r-gcjnIXWD-pDoXxPV8wqTvbS5L7VP67mag5jQ3kM5HkyTc4t41yqVmU816eHM2ec2TL3nE4W+SXnGXhaLu4ava1rK9zWs2jazK2mz2qAjqAjOAHqDWVz9nu8pgVaEFqmOmoTg6U66jOIJAA)

Both of these evaluate to false:
```ts
IsEqual<{a: 1} & {a: 1}, {a: 1}>
IsEqual<{a: 1} | {a: 1}, {a: 1}>
```

The fix is to expand the check a touch:
```ts
type IsEqual<A, B> =
    (<G>() => G extends A & G | G ? 1 : 2) extends
    (<G>() => G extends B & G | G ? 1 : 2)
    ? true
    : false;
```

---

There's also this intersection bug but I'm unaware of a fix: [TS Playground](https://www.typescriptlang.org/play?#code/C4TwDgpgBAkgzgUQI4FcCGAbAPAQQDRQBCAfFALwCwAUFFABRYDixdAlOaY1BAB7AQA7ACZwoOKAH4oARigAuKACZ2vfsLjVaDZmw5QuqwSKKSZ8pa02ngAJxQQrCgGaY4EANzVqAbyihI3Kiu5LCIQdi+aAqyAL5QAGRQvgBGCopQMQSR0QSpShmkMdQA9MW05QB6EtRAA)

This evaluates to false:

```ts
IsEqual<{a: 1} & {b: 2}, {a: 1, b: 2}>
```


Discussion:
https://github.com/Microsoft/TypeScript/issues/27024#issuecomment-845655557 has a robust solution that seems to solve this ([TS Playground][1] link). It's a much longer type though, and seemingly not perfect either.

[1]: https://www.typescriptlang.org/play?#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-XgzwUQfncDo6ATwYp0M4dAN0Ll97QXgv4-B0A6GiAGHYF20ADJAWUHU0J3gImsPZoZORsTHGHAAG9sVfpmHaf9XLUO-IMNAWg5Au2AsqG4HIwK6WgAAL5ODAPKgAeiUZ5JmmWgHM6hqz-7fn5kBfmNznnvPKv84F0zbzQuWfBdZn5mnouxa884PzAXjPJdxal+F4Xi0-PzKAAAPqAOQ2X3O5Z8wKxLhXgslZ8GV0l3HePoai7VwFtZ8P1bi3l5rBWgtmYs6V9LEXMtikBZJhr8X8tJba1NjrM3yvoc06J9Dtn7Ndvw0t0b-KWvOAU+i2AOSahEHzrISIt2DB4FW5NsLm3SVGc8P2jzgLPvfZy8tsbL2Uvrd8O9gDf3QD5g86AMooBIfQ9+19qHHmAcndAC1ibIO3vvNmwjmHNX8dI-+8dprp3xtFZC6DzrEPkfQ9h-D8gqA5A-fh3T9zTPauo9JwlgLQA
Seemingly, according to Update 1 on [this StackOverflow answer](https://stackoverflow.com/a/68963796/10292952), under TypeScript's implementation `{a: 1} & {b: 2}` and `{a: 1, b: 2}` aren't actually the same. Not sure if that means they should or shouldn't be equal on the type level, though.

microsoft/TypeScript#48100 is an open issue tracking type equality and its definition. Seems that a recursive `Simplify` can fix some issues with equality as well.
FWIW https://github.com/microsoft/TypeScript/pull/60726 might fix the intersection bug mentioned above.



Patch:
diff --git a/source/is-equal.d.ts b/source/is-equal.d.ts
index 5a8a39ba4..24c4253e0 100644
--- a/source/is-equal.d.ts
+++ b/source/is-equal.d.ts
@@ -25,7 +25,7 @@ type Includes<Value extends readonly any[], Item> =
 @category Utilities
 */
 export type IsEqual<A, B> =
-	(<G>() => G extends A ? 1 : 2) extends
-	(<G>() => G extends B ? 1 : 2)
+	(<G>() => G extends A & G | G ? 1 : 2) extends
+	(<G>() => G extends B & G | G ? 1 : 2)
 		? true
 		: false;


Test patch:
diff --git a/test-d/is-equal.ts b/test-d/is-equal.ts
index f2dcd1bbb..a41d6c962 100644
--- a/test-d/is-equal.ts
+++ b/test-d/is-equal.ts
@@ -26,3 +26,10 @@ type A = IsEqual;
 // Missing `Y` generic parameter.
 // @ts-expect-error
 type B = IsEqual<number>;
+
+// Test for issue https://github.com/sindresorhus/type-fest/issues/537
+type UnionType = IsEqual<{a: 1} & {a: 1}, {a: 1}>; // eslint-disable-line @typescript-eslint/no-duplicate-type-constituents
+expectType<UnionType>(true);
+
+type IntersectionType = IsEqual<{a: 1} | {a: 1}, {a: 1}>; // eslint-disable-line @typescript-eslint/no-duplicate-type-constituents
+expectType<IntersectionType>(true);