diff --git a/source/is-equal.d.ts b/source/is-equal.d.ts index 24c4253e0..95f3eff85 100644 --- a/source/is-equal.d.ts +++ b/source/is-equal.d.ts @@ -1,3 +1,4 @@ +import type {IsNever} from './is-never.d.ts'; /** Returns a boolean for whether the two given types are equal. @@ -25,6 +26,12 @@ type Includes = @category Utilities */ export type IsEqual = + [A, B] extends [infer A, infer B] + ? _IsEqual + : false; + +// This version fails the `equalWrappedTupleIntersectionToBeNeverAndNeverExpanded` test in `test-d/is-equal.ts`. +type _IsEqual = (() => G extends A & G | G ? 1 : 2) extends (() => G extends B & G | G ? 1 : 2) ? true diff --git a/test-d/is-equal.ts b/test-d/is-equal.ts index 5401ccea3..5656ffd2b 100644 --- a/test-d/is-equal.ts +++ b/test-d/is-equal.ts @@ -1,23 +1,51 @@ import {expectType} from 'tsd'; import type {IsEqual} from '../index.d.ts'; +import type {BuildTuple} from '../source/internal/index.d.ts'; -const notEqualNumberAndString: IsEqual = false; -expectType(notEqualNumberAndString); +expectType({} as IsEqual); +expectType({} as IsEqual<1, 1>); +expectType({} as IsEqual<'A', 'B'>); +expectType({} as IsEqual<'foo', 'foo'>); +expectType({} as IsEqual); +expectType({} as IsEqual); -const equalNumbers: IsEqual<1, 1> = true; -expectType(equalNumbers); +expectType({} as IsEqual); +expectType({} as IsEqual<'', never>); +expectType({} as IsEqual); +expectType({} as IsEqual); +expectType({} as IsEqual); +expectType({} as IsEqual); +expectType({} as IsEqual); +expectType({} as IsEqual<[any], [never]>); +expectType({} as IsEqual<[any], [any]>); +expectType({} as IsEqual<[never], [never]>); -const notEqualAnyAndNumber: IsEqual = false; -expectType(notEqualAnyAndNumber); +expectType({} as IsEqual<1 | 2, 1>); +expectType({} as IsEqual<1 | 2, 2 | 3>); +expectType({} as IsEqual<1 | 2, 2 | 1>); +expectType({} as IsEqual); -const notEqualUnionAndNumber: IsEqual<1 | 2, 1> = false; -expectType(notEqualUnionAndNumber); +expectType({} as IsEqual<{a: 1}, {a: 1}>); +expectType({} as IsEqual<{a: 1}, {a?: 1}>); +expectType({} as IsEqual<{a: 1}, {readonly a: 1}>); -const notEqualAnyAndNever: IsEqual = false; -expectType(notEqualAnyAndNever); +expectType({} as IsEqual<[], []>); +expectType({} as IsEqual); +expectType({} as IsEqual); +expectType({} as IsEqual); +expectType({} as IsEqual); +expectType({} as IsEqual); +expectType({} as IsEqual<[string], [string]>); +expectType({} as IsEqual<[string], [string, number]>); +expectType({} as IsEqual<[0, 1] | [0, 2], [0, 2]>); -const notEqualArrayOfAnyAndArrayOfNever: IsEqual<[any], [never]> = false; -expectType(notEqualArrayOfAnyAndArrayOfNever); +type LongTupleNumber = BuildTuple<50, 0>; +expectType({} as IsEqual); + +type ReadonlyLongTupleNumber = Readonly>; +expectType({} as IsEqual); + +expectType({} as IsEqual); // Missing all generic parameters. // @ts-expect-error @@ -28,8 +56,29 @@ type A = IsEqual; type B = IsEqual; // 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 +type UnionType = IsEqual<{a: 1} | {a: 1}, {a: 1}>; // eslint-disable-line @typescript-eslint/no-duplicate-type-constituents expectType(true); -type IntersectionType = IsEqual<{a: 1} | {a: 1}, {a: 1}>; // eslint-disable-line @typescript-eslint/no-duplicate-type-constituents +type IntersectionType = IsEqual<{a: 1} & {a: 1}, {a: 1}>; // eslint-disable-line @typescript-eslint/no-duplicate-type-constituents expectType(true); + +// Test for PR https://github.com/sindresorhus/type-fest/pull/1231 +type BranchOnWrappedTupleMatches = (Tpl extends [[0, 2]] ? 'Foo' : 'Bar'); +type BranchOnWrappedTupleDoesNotMatch = (Tpl extends [[0, 1]] ? 'Foo' : 'Bar'); +type BranchOnTupleMatches = (Tpl extends [0, 2] ? 'Foo' : 'Bar'); +type BranchOnTupleDoesNotMatch = (Tpl extends [0, 1] ? 'Foo' : 'Bar'); + +declare const equalWrappedTupleIntersectionToBeNeverAndNever: IsEqual<(BranchOnWrappedTupleMatches<[[0, 2]]> & BranchOnWrappedTupleDoesNotMatch<[[0, 2]]>), never>; +expectType(equalWrappedTupleIntersectionToBeNeverAndNever); + +declare const equalWrappedTupleIntersectionToBeNeverAndNeverExpanded: [0, 2] extends infer Tpl ? IsEqual<(BranchOnWrappedTupleMatches<[Tpl]> & BranchOnWrappedTupleDoesNotMatch<[Tpl]>), never> : never; +expectType(equalWrappedTupleIntersectionToBeNeverAndNeverExpanded); + +declare const equalTupleIntersectionToBeNeverAndNever: IsEqual<(BranchOnTupleMatches<[0, 2]> & BranchOnTupleDoesNotMatch<[0, 2]>), never>; +expectType(equalTupleIntersectionToBeNeverAndNever); + +declare const equalTupleIntersectionToBeNeverAndNeverExpanded: [0, 2] extends infer Tpl ? IsEqual<(BranchOnTupleMatches & BranchOnTupleDoesNotMatch), never> : never; +expectType(equalTupleIntersectionToBeNeverAndNeverExpanded); + +declare const equalTupleIntersectionAndTuple: IsEqual<[{a: 1}] & [{a: 1}], [{a: 1}]>; // eslint-disable-line @typescript-eslint/no-duplicate-type-constituents +expectType(equalTupleIntersectionAndTuple);