From 5d58998e27dc0f1512f85e3f62d97cbe4fc56f86 Mon Sep 17 00:00:00 2001 From: Takahiro Kato Date: Sun, 27 Nov 2022 00:01:22 +0900 Subject: [PATCH 1/7] Add IsEqual type --- index.d.ts | 1 + readme.md | 1 + source/conditional-pick-deep.d.ts | 2 +- source/except.d.ts | 2 +- source/includes.d.ts | 2 +- source/internal.d.ts | 12 --------- source/is-equal.d.ts | 21 ++++++++++++++++ source/multidimensional-array.d.ts | 3 ++- source/multidimensional-readonly-array.d.ts | 3 ++- test-d/is-equal.ts | 28 +++++++++++++++++++++ 10 files changed, 58 insertions(+), 17 deletions(-) create mode 100644 source/is-equal.d.ts create mode 100644 test-d/is-equal.ts diff --git a/index.d.ts b/index.d.ts index 96403b75a..298985380 100644 --- a/index.d.ts +++ b/index.d.ts @@ -74,6 +74,7 @@ export type {RequiredKeysOf} from './source/required-keys-of'; export type {HasRequiredKeys} from './source/has-required-keys'; export type {Spread} from './source/spread'; export type {TupleToUnion} from './source/tuple-to-union'; +export type {IsEqual} from './source/is-equal'; // Template literal types export type {CamelCase} from './source/camel-case'; diff --git a/readme.md b/readme.md index e575a84b8..b7e140468 100644 --- a/readme.md +++ b/readme.md @@ -183,6 +183,7 @@ Click the type names for complete docs. - [`RequiredKeysOf`](source/required-keys-of.d.ts) - Extract all required keys from the given type. - [`HasRequiredKeys`](source/has-required-keys.d.ts) - Create a `true`/`false` type depending on whether the given type has any required fields. - [`Spread`](source/spread.d.ts) - Mimic the type inferred by TypeScript when merging two objects or two arrays/tuples using the spread syntax. +- [`IsEqual`](source/is-equal.ts) - Returns a boolean for whether the two given types are equal. ### JSON diff --git a/source/conditional-pick-deep.d.ts b/source/conditional-pick-deep.d.ts index cb6ccf90f..30d09e738 100644 --- a/source/conditional-pick-deep.d.ts +++ b/source/conditional-pick-deep.d.ts @@ -1,5 +1,5 @@ import type {Opaque} from './opaque'; -import type {IsEqual} from './internal'; +import type {IsEqual} from './is-equal'; import type {ConditionalExcept} from './conditional-except'; import type {ConditionalSimplifyDeep} from './conditional-simplify'; diff --git a/source/except.d.ts b/source/except.d.ts index dab21d54c..bf1dd4154 100644 --- a/source/except.d.ts +++ b/source/except.d.ts @@ -1,4 +1,4 @@ -import type {IsEqual} from './internal'; +import type {IsEqual} from './is-equal'; /** Filter out keys from an object. diff --git a/source/includes.d.ts b/source/includes.d.ts index 610b850c0..b269dd48e 100644 --- a/source/includes.d.ts +++ b/source/includes.d.ts @@ -1,4 +1,4 @@ -import type {IsEqual} from './internal'; +import type {IsEqual} from './is-equal'; /** Returns a boolean for whether the given array includes the given item. diff --git a/source/internal.d.ts b/source/internal.d.ts index ca9ddae72..7db28ca58 100644 --- a/source/internal.d.ts +++ b/source/internal.d.ts @@ -1,17 +1,5 @@ import type {Primitive} from './primitive'; -/** -Returns a boolean for whether the two given types are equal. - -@link https://github.com/microsoft/TypeScript/issues/27024#issuecomment-421529650 -@link https://stackoverflow.com/questions/68961864/how-does-the-equals-work-in-typescript/68963796#68963796 -*/ -export type IsEqual = - (() => G extends T ? 1 : 2) extends - (() => G extends U ? 1 : 2) - ? true - : false; - /** Infer the length of the given array ``. diff --git a/source/is-equal.d.ts b/source/is-equal.d.ts new file mode 100644 index 000000000..f6a99ab6c --- /dev/null +++ b/source/is-equal.d.ts @@ -0,0 +1,21 @@ +/** +Returns a boolean for whether the two given types are equal. + +@link https://github.com/microsoft/TypeScript/issues/27024#issuecomment-421529650 +@link https://stackoverflow.com/questions/68961864/how-does-the-equals-work-in-typescript/68963796#68963796 + +@example +``` +import type {IsEqual} from 'type-fest'; + +type Expect = T +type Case = Expect, "SAMPLE">> +``` + +@category Utilities +*/ +export type IsEqual = + (() => G extends X ? 1 : 2) extends + (() => G extends Y ? 1 : 2) + ? true + : false; diff --git a/source/multidimensional-array.d.ts b/source/multidimensional-array.d.ts index f100bd1b9..f2f553968 100644 --- a/source/multidimensional-array.d.ts +++ b/source/multidimensional-array.d.ts @@ -1,4 +1,5 @@ -import type {IsEqual, Subtract} from './internal'; +import type {Subtract} from './internal'; +import type {IsEqual} from './is-equal'; type Recursive = Array>; diff --git a/source/multidimensional-readonly-array.d.ts b/source/multidimensional-readonly-array.d.ts index 92c4e2f05..5896cd2e2 100644 --- a/source/multidimensional-readonly-array.d.ts +++ b/source/multidimensional-readonly-array.d.ts @@ -1,4 +1,5 @@ -import type {IsEqual, Subtract} from './internal'; +import type {Subtract} from './internal'; +import type {IsEqual} from './is-equal'; type Recursive = ReadonlyArray>; diff --git a/test-d/is-equal.ts b/test-d/is-equal.ts new file mode 100644 index 000000000..242798d01 --- /dev/null +++ b/test-d/is-equal.ts @@ -0,0 +1,28 @@ +import {expectError, expectType} from 'tsd'; +import type {IsEqual} from '../index'; + +const notEqualNumberAndString: IsEqual = false; +expectType(notEqualNumberAndString); + +const equalNumbers: IsEqual<1, 1> = true; +expectType(equalNumbers); + +const notEqualAnyAndNumber: IsEqual = false; +expectType(notEqualAnyAndNumber); + +const notEqualUnionAndNumber: IsEqual<1 | 2, 1> = false; +expectType(notEqualUnionAndNumber); + +const notEqualAnyAndNever: IsEqual = false; +expectType(notEqualAnyAndNever); + +const notEqualArrayOfAnyAndArrayOfNever: IsEqual<[any], [never]> = false; +expectType(notEqualArrayOfAnyAndArrayOfNever); + +declare const anything: any; + +// Missing all generic parameters. +expectError(anything); + +// Missing `Y` generic parameter. +expectError>(anything); From 45c1443740914910e08d60e77421da26e358b9ab Mon Sep 17 00:00:00 2001 From: Takahiro Kato Date: Fri, 2 Dec 2022 20:32:58 +0900 Subject: [PATCH 2/7] added sample code --- source/is-equal.d.ts | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/source/is-equal.d.ts b/source/is-equal.d.ts index f6a99ab6c..5123e1ace 100644 --- a/source/is-equal.d.ts +++ b/source/is-equal.d.ts @@ -4,18 +4,34 @@ Returns a boolean for whether the two given types are equal. @link https://github.com/microsoft/TypeScript/issues/27024#issuecomment-421529650 @link https://stackoverflow.com/questions/68961864/how-does-the-equals-work-in-typescript/68963796#68963796 +@example +``` +type ExpectTrue = IsEqual<1, 1> +//=> true +``` + +@example +``` +type ExpectFalse = IsEqual<2, 1> +//=> false +``` + @example ``` import type {IsEqual} from 'type-fest'; -type Expect = T -type Case = Expect, "SAMPLE">> +type Includes = + Value extends readonly [Value[0], ...infer rest] + ? IsEqual extends true + ? true + : Includes + : false; ``` @category Utilities */ -export type IsEqual = - (() => G extends X ? 1 : 2) extends - (() => G extends Y ? 1 : 2) +export type IsEqual = + (() => G extends A ? 1 : 2) extends + (() => G extends B ? 1 : 2) ? true : false; From 44e33dfec6a60403a5087f5cc1acbfbb6e506bb3 Mon Sep 17 00:00:00 2001 From: Takahiro Kato Date: Fri, 9 Dec 2022 17:08:02 +0900 Subject: [PATCH 3/7] Add comments for code example --- source/is-equal.d.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/source/is-equal.d.ts b/source/is-equal.d.ts index 5123e1ace..551ca8631 100644 --- a/source/is-equal.d.ts +++ b/source/is-equal.d.ts @@ -6,13 +6,19 @@ Returns a boolean for whether the two given types are equal. @example ``` -type ExpectTrue = IsEqual<1, 1> +import type {IsEqual} from 'type-fest'; + +// `IsEqual` compares 1 and 1, then gets true as a result. +type ExpectTrue = IsEqual<1, 1>; //=> true ``` @example ``` -type ExpectFalse = IsEqual<2, 1> +import type {IsEqual} from 'type-fest'; + +// `IsEqual` compares 2 and 1, then gets false as a result. +type ExpectFalse = IsEqual<2, 1>; //=> false ``` @@ -20,6 +26,8 @@ type ExpectFalse = IsEqual<2, 1> ``` import type {IsEqual} from 'type-fest'; +// `Includes` Returns a boolean for whether the given array includes the given item. +// `IsEqual` compares the given array of 0th and the given item, then return true if they are equal. type Includes = Value extends readonly [Value[0], ...infer rest] ? IsEqual extends true From 081aad2d5f009760b8ee2981cdbe4739263076d3 Mon Sep 17 00:00:00 2001 From: Takahiro Kato Date: Wed, 14 Dec 2022 00:30:50 +0900 Subject: [PATCH 4/7] Deleted unnecessary examples --- source/is-equal.d.ts | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/source/is-equal.d.ts b/source/is-equal.d.ts index 551ca8631..7187fa1b3 100644 --- a/source/is-equal.d.ts +++ b/source/is-equal.d.ts @@ -8,24 +8,6 @@ Returns a boolean for whether the two given types are equal. ``` import type {IsEqual} from 'type-fest'; -// `IsEqual` compares 1 and 1, then gets true as a result. -type ExpectTrue = IsEqual<1, 1>; -//=> true -``` - -@example -``` -import type {IsEqual} from 'type-fest'; - -// `IsEqual` compares 2 and 1, then gets false as a result. -type ExpectFalse = IsEqual<2, 1>; -//=> false -``` - -@example -``` -import type {IsEqual} from 'type-fest'; - // `Includes` Returns a boolean for whether the given array includes the given item. // `IsEqual` compares the given array of 0th and the given item, then return true if they are equal. type Includes = From 401ad60676f4fb8b3c7770eeaaa7dc6b775ff201 Mon Sep 17 00:00:00 2001 From: Takahiro Kato Date: Sun, 25 Dec 2022 19:33:32 +0900 Subject: [PATCH 5/7] use cases added as documentation --- source/is-equal.d.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/is-equal.d.ts b/source/is-equal.d.ts index 7187fa1b3..93104c7b1 100644 --- a/source/is-equal.d.ts +++ b/source/is-equal.d.ts @@ -4,6 +4,9 @@ Returns a boolean for whether the two given types are equal. @link https://github.com/microsoft/TypeScript/issues/27024#issuecomment-421529650 @link https://stackoverflow.com/questions/68961864/how-does-the-equals-work-in-typescript/68963796#68963796 +Use-cases: +- If you want to make a conditional branch based on the result of a comparison of two types. + @example ``` import type {IsEqual} from 'type-fest'; From bec397dbb2c5045bfed4a31001941bd23adfdc52 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sun, 25 Dec 2022 23:48:43 +0100 Subject: [PATCH 6/7] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index e93462459..6a5d0b32c 100644 --- a/readme.md +++ b/readme.md @@ -169,7 +169,7 @@ Click the type names for complete docs. - [`RequiredKeysOf`](source/required-keys-of.d.ts) - Extract all required keys from the given type. - [`HasRequiredKeys`](source/has-required-keys.d.ts) - Create a `true`/`false` type depending on whether the given type has any required fields. - [`Spread`](source/spread.d.ts) - Mimic the type inferred by TypeScript when merging two objects or two arrays/tuples using the spread syntax. -- [`IsEqual`](source/is-equal.ts) - Returns a boolean for whether the two given types are equal. +- [`IsEqual`](source/is-equal.d.ts) - Returns a boolean for whether the two given types are equal. ### JSON From f18d00c825a142a5386998289daf686547815f63 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sun, 25 Dec 2022 23:52:07 +0100 Subject: [PATCH 7/7] Update is-equal.d.ts --- source/is-equal.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/is-equal.d.ts b/source/is-equal.d.ts index 93104c7b1..4a64dda57 100644 --- a/source/is-equal.d.ts +++ b/source/is-equal.d.ts @@ -11,8 +11,8 @@ Use-cases: ``` import type {IsEqual} from 'type-fest'; -// `Includes` Returns a boolean for whether the given array includes the given item. -// `IsEqual` compares the given array of 0th and the given item, then return true if they are equal. +// This type returns a boolean for whether the given array includes the given item. +// `IsEqual` is used to compare the given array at position 0 and the given item and then return true if they are equal. type Includes = Value extends readonly [Value[0], ...infer rest] ? IsEqual extends true