From 33c02089f5d2f4c0cd02ce29051c0668e50a1446 Mon Sep 17 00:00:00 2001 From: unional Date: Tue, 3 Oct 2023 23:14:02 -0700 Subject: [PATCH] feat: update IsFunction types --- .changeset/large-windows-obey.md | 7 ++ .../ts/bigint/is_not_strict_bigint.spec.ts | 5 +- type-plus/ts/bigint/is_not_strict_bigint.ts | 15 ++-- type-plus/ts/bigint/is_strict_bigint.spec.ts | 4 +- type-plus/ts/bigint/is_strict_bigint.ts | 18 ++-- .../ts/boolean/is_not_strict_boolean.spec.ts | 1 + type-plus/ts/boolean/is_not_strict_boolean.ts | 4 +- type-plus/ts/boolean/is_strict_boolean.ts | 12 +-- .../function_type.is_not_function.spec.ts | 59 ------------ .../function_type.not_function_type.spec.ts | 57 ------------ type-plus/ts/function/function_type.spec.ts | 59 ------------ type-plus/ts/function/function_type.ts | 67 -------------- ...s_function.spec.ts => is_function.spec.ts} | 40 ++++++--- type-plus/ts/function/is_function.ts | 23 +++++ type-plus/ts/function/is_not_function.spec.ts | 80 +++++++++++++++++ type-plus/ts/function/is_not_function.ts | 22 +++++ .../function/is_not_strict_function.spec.ts | 89 +++++++++++++++++++ .../ts/function/is_not_strict_function.ts | 40 +++++++++ .../ts/function/is_strict_function.spec.ts | 77 ++++++++++++++++ type-plus/ts/function/is_strict_function.ts | 40 +++++++++ ...nction_type.is_not_strict_function.spec.ts | 59 ------------ ...t_function_type.is_strict_function.spec.ts | 59 ------------ ...tion_type.not_strict_function_type.spec.ts | 60 ------------- .../ts/function/strict_function_type.spec.ts | 60 ------------- type-plus/ts/function/strict_function_type.ts | 55 ------------ type-plus/ts/index.ts | 11 +-- type-plus/ts/mix_types/box.ts | 50 ++++++----- .../select_invert_strict_with_distribute.ts | 15 +++- .../branch/select_strict_with_distribute.ts | 84 +++++++++++++++++ 29 files changed, 563 insertions(+), 609 deletions(-) create mode 100644 .changeset/large-windows-obey.md delete mode 100644 type-plus/ts/function/function_type.is_not_function.spec.ts delete mode 100644 type-plus/ts/function/function_type.not_function_type.spec.ts delete mode 100644 type-plus/ts/function/function_type.spec.ts delete mode 100644 type-plus/ts/function/function_type.ts rename type-plus/ts/function/{function_type.is_function.spec.ts => is_function.spec.ts} (50%) create mode 100644 type-plus/ts/function/is_function.ts create mode 100644 type-plus/ts/function/is_not_function.spec.ts create mode 100644 type-plus/ts/function/is_not_function.ts create mode 100644 type-plus/ts/function/is_not_strict_function.spec.ts create mode 100644 type-plus/ts/function/is_not_strict_function.ts create mode 100644 type-plus/ts/function/is_strict_function.spec.ts create mode 100644 type-plus/ts/function/is_strict_function.ts delete mode 100644 type-plus/ts/function/strict_function_type.is_not_strict_function.spec.ts delete mode 100644 type-plus/ts/function/strict_function_type.is_strict_function.spec.ts delete mode 100644 type-plus/ts/function/strict_function_type.not_strict_function_type.spec.ts delete mode 100644 type-plus/ts/function/strict_function_type.spec.ts delete mode 100644 type-plus/ts/function/strict_function_type.ts create mode 100644 type-plus/ts/type_plus/branch/select_strict_with_distribute.ts diff --git a/.changeset/large-windows-obey.md b/.changeset/large-windows-obey.md new file mode 100644 index 0000000000..d1517ed0de --- /dev/null +++ b/.changeset/large-windows-obey.md @@ -0,0 +1,7 @@ +--- +"type-plus": minor +--- + +Update `IsFunction`, `IsNotFunction`, `IsStrictFunction`, `IsNotStrictFunction`. + +Remove `FunctionType`, `NotFunctionType`, `StrictFunctionType`, `NotStrictFunctionType`. diff --git a/type-plus/ts/bigint/is_not_strict_bigint.spec.ts b/type-plus/ts/bigint/is_not_strict_bigint.spec.ts index 5b38050076..e84bb77010 100644 --- a/type-plus/ts/bigint/is_not_strict_bigint.spec.ts +++ b/type-plus/ts/bigint/is_not_strict_bigint.spec.ts @@ -43,8 +43,9 @@ it('can disable union distribution', () => { testType.equal, true>(true) }) -it('consider intersection type as not strict', () => { - testType.true>(true) +it('consider intersection type as strict', () => { + testType.false>(true) + testType.true>(true) }) it('works as filter', () => { diff --git a/type-plus/ts/bigint/is_not_strict_bigint.ts b/type-plus/ts/bigint/is_not_strict_bigint.ts index f4a04f01ef..882033a25f 100644 --- a/type-plus/ts/bigint/is_not_strict_bigint.ts +++ b/type-plus/ts/bigint/is_not_strict_bigint.ts @@ -63,17 +63,16 @@ export type IsNotStrictBigint< : IsNotStrictBigint._N) : never : never - export namespace IsNotStrictBigint { +export namespace IsNotStrictBigint { export type $Options = SelectWithDistribute.$Options export type $Default = SelectWithDistribute.$Default export type $Branch = SelectWithDistribute.$Branch - export type _D = (bigint extends T - ? (T extends bigint - ? (`${T}` extends `${number}` - ? $ResolveSelection<$O, T, $Then> - : $ResolveSelection<$O, T, $Else>) - : $ResolveSelection<$O, T, $Then>) - : $ResolveSelection<$O, T, $Then>) + export type _D = + T extends bigint + ? (`${T}` extends `${number}` + ? $ResolveSelection<$O, T, $Then> + : $ResolveSelection<$O, T, $Else>) + : $ResolveSelection<$O, T, $Then> export type _N = ([bigint, T] extends [T, bigint] ? (T extends bigint ? (`${T}` extends `${number}` diff --git a/type-plus/ts/bigint/is_strict_bigint.spec.ts b/type-plus/ts/bigint/is_strict_bigint.spec.ts index 0624d6b375..e7f35fdc13 100644 --- a/type-plus/ts/bigint/is_strict_bigint.spec.ts +++ b/type-plus/ts/bigint/is_strict_bigint.spec.ts @@ -43,8 +43,8 @@ it('can disable union distribution', () => { testType.equal, false>(true) }) -it('consider intersection type as not strict', () => { - testType.false>(true) +it('consider intersection type as strict', () => { + testType.true>(true) testType.false>(true) }) diff --git a/type-plus/ts/bigint/is_strict_bigint.ts b/type-plus/ts/bigint/is_strict_bigint.ts index 54670acc79..b53f12dce4 100644 --- a/type-plus/ts/bigint/is_strict_bigint.ts +++ b/type-plus/ts/bigint/is_strict_bigint.ts @@ -70,14 +70,16 @@ export namespace IsStrictBigint { export type $Options = SelectWithDistribute.$Options export type $Default = SelectWithDistribute.$Default export type $Branch = SelectWithDistribute.$Branch - export type _D = (bigint extends T - ? (T extends bigint - ? (`${T}` extends `${number}` - ? $ResolveSelection<$O, T, $Else> - : $ResolveSelection<$O, T, $Then>) - : $ResolveSelection<$O, T, $Else>) - : $ResolveSelection<$O, T, $Else>) - export type _N = ([bigint, T] extends [T, bigint] + export type _D = + T extends bigint + ? ( + `${T}` extends `${number}` + ? $ResolveSelection<$O, T, $Else> + : $ResolveSelection<$O, T, $Then> + ) + : $ResolveSelection<$O, T, $Else> + export type _N = ( + [bigint, T] extends [T, bigint] ? (T extends bigint ? (`${T}` extends `${number}` ? $ResolveSelection<$O, T, $Else> diff --git a/type-plus/ts/boolean/is_not_strict_boolean.spec.ts b/type-plus/ts/boolean/is_not_strict_boolean.spec.ts index 7c4b97aa0d..5d213683e4 100644 --- a/type-plus/ts/boolean/is_not_strict_boolean.spec.ts +++ b/type-plus/ts/boolean/is_not_strict_boolean.spec.ts @@ -46,6 +46,7 @@ it('can disable union distribution', () => { }) it('returns false for intersection type', () => { + // `boolean & { a: 1 }` is considered as strict boolean testType.equal, false>(true) }) diff --git a/type-plus/ts/boolean/is_not_strict_boolean.ts b/type-plus/ts/boolean/is_not_strict_boolean.ts index 1818295d2f..cedfbf0f44 100644 --- a/type-plus/ts/boolean/is_not_strict_boolean.ts +++ b/type-plus/ts/boolean/is_not_strict_boolean.ts @@ -18,7 +18,7 @@ import type { IsStrictBoolean } from './is_strict_boolean.js' * type R = IsNotStrictBoolean // true * type R = IsNotStrictBoolean // true * type R = IsNotStrictBoolean // boolean - * ``` + * ``` * * 🔢 *customize* * @@ -71,7 +71,7 @@ export type IsNotStrictBoolean = : ['aBcd' | 'Abcd'] extends [R] ? $ResolveSelection<$O, T, $Else> : $ResolveSelection<$O, T, $Then> : never ) - : [T, boolean] extends [boolean, T] ? $ResolveSelection<$O, T, $Else> : $ResolveSelection<$O, T, $Then> + : SelectInvertStrictWithDistribute._N ) : never : never diff --git a/type-plus/ts/boolean/is_strict_boolean.ts b/type-plus/ts/boolean/is_strict_boolean.ts index 3078f1ef82..0252b5cb30 100644 --- a/type-plus/ts/boolean/is_strict_boolean.ts +++ b/type-plus/ts/boolean/is_strict_boolean.ts @@ -1,5 +1,5 @@ import type { IsAnyOrNever } from '../mix_types/is_any_or_never.js' -import type { SelectInvertStrictWithDistribute } from '../type_plus/branch/select_invert_strict_with_distribute.js' +import type { SelectStrictWithDistribute } from '../type_plus/branch/select_strict_with_distribute.js' import type { $Else, $ResolveSelection, $SelectionBranch, $Then } from '../type_plus/branch/selection.js' import type { $ResolveOptions } from '../type_plus/resolve_options.js' @@ -63,7 +63,7 @@ export type IsStrictBoolean = IsAny > extends infer R ? R extends $Then ? $ResolveSelection<$O, T, $Else> : R extends $Else ? ( - $ResolveOptions<[$O['distributive'], SelectInvertStrictWithDistribute.$Default['distributive']]> extends true + $ResolveOptions<[$O['distributive'], SelectStrictWithDistribute.$Default['distributive']]> extends true ? ( IsStrictBoolean._DistributeMap extends infer R ? ['aBcD' | 'AbCd' | 'abcd'] extends [R] ? $ResolveSelection<$O, boolean, $Then> | $ResolveSelection<$O, Exclude, $Else> @@ -71,14 +71,14 @@ export type IsStrictBoolean = IsAny : ['aBcd' | 'Abcd'] extends [R] ? $ResolveSelection<$O, T, $Then> : $ResolveSelection<$O, T, $Else> : never ) - : [T, boolean] extends [boolean, T] ? $ResolveSelection<$O, T, $Then> : $ResolveSelection<$O, T, $Else> + : SelectStrictWithDistribute._N ) : never : never export namespace IsStrictBoolean { - export type $Options = SelectInvertStrictWithDistribute.$Options - export type $Default = SelectInvertStrictWithDistribute.$Default - export type $Branch = SelectInvertStrictWithDistribute.$Branch + export type $Options = SelectStrictWithDistribute.$Options + export type $Default = SelectStrictWithDistribute.$Default + export type $Branch = SelectStrictWithDistribute.$Branch export type _DistributeMap = T extends true ? (T extends false diff --git a/type-plus/ts/function/function_type.is_not_function.spec.ts b/type-plus/ts/function/function_type.is_not_function.spec.ts deleted file mode 100644 index 541d308a9b..0000000000 --- a/type-plus/ts/function/function_type.is_not_function.spec.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { it } from '@jest/globals' -import { testType, type AnyFunction, type IsNotFunction } from '../index.js' - -it('returns false if T is Function', () => { - testType.false>(true) -}) - -it('returns false if T is function signature', () => { - testType.false void>>(true) - testType.false>(true) -}) - -it('returns true for special types', () => { - testType.true>(true) - testType.true>(true) - testType.true>(true) - testType.true>(true) -}) - -it('returns true for all other types', () => { - testType.true>(true) - testType.true>(true) - testType.true>(true) - testType.true>(true) - testType.true>(true) - testType.true>(true) - testType.true>(true) - testType.true>(true) - testType.true>(true) - testType.true>(true) - testType.true>(true) - testType.true>(true) - testType.true>(true) - testType.true>(true) - testType.true>(true) - testType.true>(true) -}) - -it('returns true if T is union of function and other types', () => { - testType.true>(true) -}) - -it('returns false if T is function overloads', () => { - testType.false>(true) -}) - -it('returns false if T is intersection of function', () => { - testType.false>(true) -}) - -it('can override Then/Else', () => { - testType.equal, 2>(true) - testType.equal, 1>(true) - - testType.equal, 1>(true) - testType.equal, 1>(true) - testType.equal, 1>(true) - testType.equal, 1>(true) -}) diff --git a/type-plus/ts/function/function_type.not_function_type.spec.ts b/type-plus/ts/function/function_type.not_function_type.spec.ts deleted file mode 100644 index d50b3eeb36..0000000000 --- a/type-plus/ts/function/function_type.not_function_type.spec.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { it } from '@jest/globals' -import { testType, type AnyFunction, type NotFunctionType } from '../index.js' - -it('returns never if T is Function', () => { - testType.never>(true) -}) - -it('returns never if T is function signature', () => { - testType.never void>>(true) - testType.never>(true) -}) - -it('returns T for special types', () => { - testType.equal, void>(true) - testType.equal, unknown>(true) - testType.equal, any>(true) - testType.equal, never>(true) -}) - -it('returns T for all other types', () => { - testType.equal, undefined>(true) - testType.equal, null>(true) - testType.equal, boolean>(true) - testType.equal, true>(true) - testType.equal, false>(true) - testType.equal, number>(true) - testType.equal, 1>(true) - testType.equal, string>(true) - testType.equal, ''>(true) - testType.equal, symbol>(true) - testType.equal, bigint>(true) - testType.equal, {}>(true) - testType.equal, string[]>(true) - testType.equal, []>(true) -}) - -it('returns T if T is union of function and other types', () => { - testType.equal, Function | { a: 1 }>(true) -}) - -it('returns never if T is function overloads', () => { - testType.never>(true) -}) - -it('returns never if T is intersection of function', () => { - testType.never>(true) -}) - -it('can override Then/Else', () => { - testType.equal, 2>(true) - testType.equal, 1>(true) - - testType.equal, 1>(true) - testType.equal, 1>(true) - testType.equal, 1>(true) - testType.equal, 1>(true) -}) diff --git a/type-plus/ts/function/function_type.spec.ts b/type-plus/ts/function/function_type.spec.ts deleted file mode 100644 index 8d8c21b81b..0000000000 --- a/type-plus/ts/function/function_type.spec.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { it } from '@jest/globals' -import { testType, type AnyFunction, type FunctionType } from '../index.js' - -it('returns T if T is Function', () => { - testType.equal, Function>(true) -}) - -it('returns T if T is a function signature', () => { - testType.equal void>, () => void>(true) - testType.equal, AnyFunction>(true) -}) - -it('returns never for special types', () => { - testType.never>(true) - testType.never>(true) - testType.never>(true) - testType.never>(true) -}) - -it('returns never for other types', () => { - testType.never>(true) - testType.never>(true) - testType.never>(true) - testType.never>(true) - testType.never>(true) - testType.never>(true) - testType.never>(true) - testType.never>(true) - testType.never>(true) - testType.never>(true) - testType.never>(true) - testType.never>(true) - testType.never>(true) - testType.never>(true) -}) - -it('returns never if T is union of function and other types', () => { - testType.never>(true) -}) - -it('returns T if T is function overloads', () => { - testType.equal, { (): void, (x: number): number }>(true) - testType.equal, { (): void, a: 1 }>(true) -}) - -it('returns T if T is intersection of function', () => { - testType.equal, Function & { a: 1 }>(true) - testType.equal, Function & 1>(true) -}) - -it('can override Then/Else', () => { - testType.equal, 1>(true) - testType.equal, 2>(true) - - testType.equal, 2>(true) - testType.equal, 2>(true) - testType.equal, 2>(true) - testType.equal, 2>(true) -}) diff --git a/type-plus/ts/function/function_type.ts b/type-plus/ts/function/function_type.ts deleted file mode 100644 index 8fc8950e9e..0000000000 --- a/type-plus/ts/function/function_type.ts +++ /dev/null @@ -1,67 +0,0 @@ -import type { IsAnyOrNever } from '../mix_types/is_any_or_never.js' -import type { $Else, $SelectionBranch, $Then } from '../type_plus/branch/selection.js' - -/** - * Check if `T` is a `Function`. - * - * ```ts - * type R = FunctionType // Function - * type R = FunctionType<() => void> // () => void - * type R = FunctionType<(() => void) | { a: 1 }> // (() => void) | { a: 1 } - * - * type R = FunctionType<{ a: 1 }> // never - * type R = FunctionType // never - * type R = FunctionType // never - * ``` - */ -export type FunctionType = IsAnyOrNever< - T, - $SelectionBranch -> extends infer R - ? R extends $Then ? Else - : R extends $Else ? [T] extends [Function] ? Then : Else - : never : never - -/** - * Is `T` a `Function`. - * - * ```ts - * type R = IsFunction // Function - * type R = IsFunction<() => void> // () => void - * type R = IsFunction<(() => void) | { a: 1 }> // (() => void) | { a: 1 } - * - * type R = IsFunction<{ a: 1 }> // never - * type R = IsFunction // never - * type R = IsFunction // never - * ``` - */ -export type IsFunction = FunctionType - -/** - * Check if `T` is not a `Function`. - * - * ```ts - * type R = NotFunctionType // never - * type R = NotFunctionType<() => void> // never - * type R = NotFunctionType<(() => void) | { a: 1 }> // never - * - * type R = NotFunctionType<{ a: 1 }> // { a: 1 } - * type R = NotFunctionType // never - * type R = NotFunctionType // unknown - * ``` - */ -export type NotFunctionType = FunctionType - -/** - * Is `T` not a `Function`. - * - * ```ts - * type R = IsNotFunction // false - * type R = IsNotFunction<() => void> // false - * type R = IsNotFunction<(() => void) | { a: 1 }> // false - * - * type R = IsNotFunction<{ a: 1 }> // true - * type R = IsNotFunction // true - * ``` - */ -export type IsNotFunction = FunctionType diff --git a/type-plus/ts/function/function_type.is_function.spec.ts b/type-plus/ts/function/is_function.spec.ts similarity index 50% rename from type-plus/ts/function/function_type.is_function.spec.ts rename to type-plus/ts/function/is_function.spec.ts index f5f93aa90e..393adc24e2 100644 --- a/type-plus/ts/function/function_type.is_function.spec.ts +++ b/type-plus/ts/function/is_function.spec.ts @@ -1,5 +1,5 @@ import { it } from '@jest/globals' -import { testType, type AnyFunction, type IsFunction } from '../index.js' +import { testType, type AnyFunction, type IsFunction, type $Then, type $Else } from '../index.js' it('returns true if T is Function', () => { testType.true>(true) @@ -11,9 +11,9 @@ it('returns true if T is function signature', () => { }) it('returns false for special types', () => { - testType.false>(true) - testType.false>(true) testType.false>(true) + testType.false>(true) + testType.false>(true) testType.false>(true) }) @@ -36,8 +36,25 @@ it('returns false for all other types', () => { testType.false>(true) }) -it('returns false if T is union of function', () => { - testType.false>(true) +it('works as filter', () => { + testType.equal, Function>(true) + testType.equal void, { selection: 'filter' }>, () => void>(true) + + testType.equal, never>(true) + testType.equal, never>(true) + testType.equal, never>(true) + + testType.equal, Function>(true) + testType.equal string), { selection: 'filter' }>, () => string>(true) +}) + +it('distributes over union type', () => { + testType.equal(true) + testType.equal, boolean>(true) +}) + +it('can disable union distribution', () => { + testType.false>(true) }) it('returns true if T is function overloads', () => { @@ -48,11 +65,12 @@ it('returns true if T is intersection of function', () => { testType.true>(true) }) -it('can override Then/Else', () => { - testType.equal, 1>(true) +it('works with unique branches', () => { + testType.equal, $Then>(true) + testType.equal boolean, IsFunction.$Branch>, $Then>(true) - testType.equal, 2>(true) - testType.equal, 2>(true) - testType.equal, 2>(true) - testType.equal, 2>(true) + testType.equal, $Else>(true) + testType.equal, $Else>(true) + testType.equal, $Else>(true) + testType.equal, $Else>(true) }) diff --git a/type-plus/ts/function/is_function.ts b/type-plus/ts/function/is_function.ts new file mode 100644 index 0000000000..f4abc624e1 --- /dev/null +++ b/type-plus/ts/function/is_function.ts @@ -0,0 +1,23 @@ +import type { SelectWithDistribute } from '../type_plus/branch/select_with_distribute.js' + +/** + * Is `T` a `Function`. + * + * ```ts + * type R = IsFunction // Function + * type R = IsFunction<() => void> // () => void + * type R = IsFunction<(() => void) | { a: 1 }> // (() => void) | { a: 1 } + * + * type R = IsFunction<{ a: 1 }> // never + * type R = IsFunction // never + * type R = IsFunction // never + * ``` + */ + +export type IsFunction = SelectWithDistribute + +export namespace IsFunction { + export type $Options = SelectWithDistribute.$Options + export type $Default = SelectWithDistribute.$Default + export type $Branch = SelectWithDistribute.$Branch +} diff --git a/type-plus/ts/function/is_not_function.spec.ts b/type-plus/ts/function/is_not_function.spec.ts new file mode 100644 index 0000000000..bc775044d8 --- /dev/null +++ b/type-plus/ts/function/is_not_function.spec.ts @@ -0,0 +1,80 @@ +import { it } from '@jest/globals' +import { testType, type AnyFunction, type IsNotFunction, type $Else, type $Then } from '../index.js' + +it('returns false if T is Function', () => { + testType.false>(true) +}) + +it('returns false if T is function signature', () => { + testType.false void>>(true) + testType.false>(true) +}) + +it('returns true for special types', () => { + testType.true>(true) + testType.true>(true) + testType.true>(true) + testType.true>(true) +}) + +it('returns true for all other types', () => { + testType.true>(true) + testType.true>(true) + testType.true>(true) + testType.true>(true) + testType.true>(true) + testType.true>(true) + testType.true>(true) + testType.true>(true) + testType.true>(true) + testType.true>(true) + testType.true>(true) + testType.true>(true) + testType.true>(true) + testType.true>(true) + testType.true>(true) + testType.true>(true) +}) + +it('distributes over union type', () => { + testType.equal, boolean>(true) + testType.equal void) | string>, boolean>(true) +}) + + +it('returns false if T is function overloads', () => { + testType.false>(true) +}) + +it('returns false if T is intersection of function', () => { + testType.false>(true) +}) + +it('can disable union distribution', () => { + testType.equal, boolean>(true) + testType.equal, true>(true) + testType.true>(true) +}) + +it('works as filter', () => { + testType.equal, never>(true) + testType.equal boolean, { selection: 'filter' }>, never>(true) + + testType.equal, never>(true) + testType.equal, unknown>(true) + testType.equal, boolean>(true) + + testType.equal, 1>(true) +}) + +it('works with unique branches', () => { + testType.equal, $Else>(true) + testType.equal void, IsNotFunction.$Branch>, $Else>(true) + + testType.equal, $Then>(true) + testType.equal, $Then>(true) + testType.equal, $Then>(true) + testType.equal, $Then>(true) + + testType.equal, $Then | $Else>(true) +}) diff --git a/type-plus/ts/function/is_not_function.ts b/type-plus/ts/function/is_not_function.ts new file mode 100644 index 0000000000..50e1237da7 --- /dev/null +++ b/type-plus/ts/function/is_not_function.ts @@ -0,0 +1,22 @@ +import type { SelectInvertWithDistribute } from '../type_plus/branch/select_invert_with_distribute.js' + +/** + * Is `T` not a `Function`. + * + * ```ts + * type R = IsNotFunction // false + * type R = IsNotFunction<() => void> // false + * type R = IsNotFunction<(() => void) | { a: 1 }> // false + * + * type R = IsNotFunction<{ a: 1 }> // true + * type R = IsNotFunction // true + * ``` + */ + +export type IsNotFunction = SelectInvertWithDistribute + +export namespace IsNotFunction { + export type $Options = SelectInvertWithDistribute.$Options + export type $Default = SelectInvertWithDistribute.$Default + export type $Branch = SelectInvertWithDistribute.$Branch +} diff --git a/type-plus/ts/function/is_not_strict_function.spec.ts b/type-plus/ts/function/is_not_strict_function.spec.ts new file mode 100644 index 0000000000..4a0c2b1409 --- /dev/null +++ b/type-plus/ts/function/is_not_strict_function.spec.ts @@ -0,0 +1,89 @@ +import { it } from '@jest/globals' +import { testType, type $Else, type $Then, type AnyFunction, type IsNotStrictFunction } from '../index.js' + +it('returns false if T is Function', () => { + testType.false>(true) +}) + +it('returns true if T is function signature', () => { + testType.true void>>(true) + testType.true>(true) +}) + +it('returns true for special types', () => { + testType.true>(true) + testType.true>(true) + testType.true>(true) + testType.true>(true) +}) + +it('returns true for all other types', () => { + testType.true>(true) + testType.true>(true) + testType.true>(true) + testType.true>(true) + testType.true>(true) + testType.true>(true) + testType.true>(true) + testType.true>(true) + testType.true>(true) + testType.true>(true) + testType.true>(true) + testType.true>(true) + testType.true>(true) + testType.true>(true) + testType.true>(true) + testType.true>(true) +}) + +it('distributes over union type', () => { + testType.equal(true) + // `false | true` -> `boolean` + testType.equal, boolean>(true) + // `true | true` -> `true` + testType.equal void) | { a: 1 }>, true>(true) +}) + +it('can disable union distribution', () => { + testType.equal, true>(true) +}) + +it('returns true if T is function overloads', () => { + testType.true>(true) + testType.true>(true) +}) + +it('returns true if T is function overloads', () => { + testType.true>(true) +}) + +it('returns false if T is intersection of function', () => { + testType.false>(true) +}) + +it('returns true for intersection type', () => { + // `Function & { a: 1 }` is considered as strict Function + testType.equal, false>(true) +}) + +it('works as filter', () => { + testType.equal, never>(true) + testType.equal void, { selection: 'filter' }>, () => void>(true) + + testType.equal, never>(true) + testType.equal, unknown>(true) + testType.equal, number>(true) + testType.equal, Function | number>(true) + + testType.equal, true>(true) +}) + +it('works with unique branches', () => { + testType.equal, $Else>(true) + testType.equal void, IsNotStrictFunction.$Branch>, $Then>(true) + + testType.equal, $Then>(true) + testType.equal, $Then>(true) + testType.equal, $Then>(true) + testType.equal, $Then>(true) +}) diff --git a/type-plus/ts/function/is_not_strict_function.ts b/type-plus/ts/function/is_not_strict_function.ts new file mode 100644 index 0000000000..fe72aaf0de --- /dev/null +++ b/type-plus/ts/function/is_not_strict_function.ts @@ -0,0 +1,40 @@ +import type { IsAnyOrNever } from '../mix_types/is_any_or_never.js' +import type { SelectInvertStrictWithDistribute } from '../type_plus/branch/select_invert_strict_with_distribute.js' +import type { $Else, $ResolveSelection, $SelectionBranch, $Then } from '../type_plus/branch/selection.js' +import type { $ResolveOptions } from '../type_plus/resolve_options.js' + +/** + * Is `T` not exactly `Function`. + * + * ```ts + * type R = IsNotStrictFunction // false + * + * type R = IsNotStrictFunction<() => void> // true + * type R = IsNotStrictFunction<(() => void) & { a: 1 }> // true + * ``` + */ + +export type IsNotStrictFunction = + IsAnyOrNever< + T, + $SelectionBranch + > extends infer R + ? R extends $Then ? $ResolveSelection<$O, T, $Then> + : R extends $Else ? ( + $ResolveOptions<[$O['distributive'], SelectInvertStrictWithDistribute.$Default['distributive']]> extends true + ? IsNotStrictFunction._D + : SelectInvertStrictWithDistribute._N + ) + : never : never + +export namespace IsNotStrictFunction { + export type $Options = SelectInvertStrictWithDistribute.$Options + export type $Default = SelectInvertStrictWithDistribute.$Default + export type $Branch = SelectInvertStrictWithDistribute.$Branch + export type _D = + T extends Function + ? T extends (...args: any[]) => any + ? $ResolveSelection<$O, T, $Then> + : $ResolveSelection<$O, T, $Else> + : $ResolveSelection<$O, T, $Then> +} diff --git a/type-plus/ts/function/is_strict_function.spec.ts b/type-plus/ts/function/is_strict_function.spec.ts new file mode 100644 index 0000000000..a787386096 --- /dev/null +++ b/type-plus/ts/function/is_strict_function.spec.ts @@ -0,0 +1,77 @@ +import { it } from '@jest/globals' +import { testType, type AnyFunction, type IsStrictFunction, type $Then, type $Else } from '../index.js' + +it('returns true if T is Function', () => { + testType.true>(true) +}) + +it('returns false if T is function signature', () => { + testType.false void>>(true) + testType.false>(true) +}) + +it('returns false for special types', () => { + testType.false>(true) + testType.false>(true) + testType.false>(true) + testType.false>(true) +}) + +it('returns false for all other types', () => { + testType.false>(true) + testType.false>(true) + testType.false>(true) + testType.false>(true) + testType.false>(true) + testType.false>(true) + testType.false>(true) + testType.false>(true) + testType.false>(true) + testType.false>(true) + testType.false>(true) + testType.false>(true) + testType.false>(true) + testType.false>(true) + testType.false>(true) + testType.false>(true) +}) + +it('distributes over union type', () => { + testType.equal(true) + testType.equal, boolean>(true) + testType.equal void) | { a: 1 }>, false>(true) +}) + +it('returns false if T is function overloads', () => { + testType.false>(true) +}) + +it('can disable union distribution', () => { + testType.equal, false>(true) +}) + +it('returns true for intersection type', () => { + testType.equal, true>(true) +}) + +it('works as filter', () => { + testType.equal, Function>(true) + testType.equal void, { selection: 'filter' }>, never>(true) + + testType.equal, never>(true) + testType.equal, never>(true) + testType.equal, Function>(true) + testType.equal, never>(true) + + testType.equal, Function>(true) +}) + +it('works with unique branches', () => { + testType.equal, $Then>(true) + testType.equal void, IsStrictFunction.$Branch>, $Else>(true) + + testType.equal, $Else>(true) + testType.equal, $Else>(true) + testType.equal, $Else>(true) + testType.equal, $Else>(true) +}) diff --git a/type-plus/ts/function/is_strict_function.ts b/type-plus/ts/function/is_strict_function.ts new file mode 100644 index 0000000000..636fee43f9 --- /dev/null +++ b/type-plus/ts/function/is_strict_function.ts @@ -0,0 +1,40 @@ +import type { IsAnyOrNever } from '../mix_types/is_any_or_never.js' +import type { SelectStrictWithDistribute } from '../type_plus/branch/select_strict_with_distribute.js' +import type { $Else, $ResolveSelection, $SelectionBranch, $Then } from '../type_plus/branch/selection.js' +import type { $ResolveOptions } from '../type_plus/resolve_options.js' + +/** + * Is `T` exactly `Function`. + * + * ```ts + * type R = IsStrictFunction // true + * + * type R = IsStrictFunction<() => void> // false + * type R = IsStrictFunction<(() => void) & { a: 1 }> // false + * ``` + */ + +export type IsStrictFunction = + IsAnyOrNever< + T, + $SelectionBranch + > extends infer R + ? R extends $Then ? $ResolveSelection<$O, T, $Else> + : R extends $Else ? ( + $ResolveOptions<[$O['distributive'], SelectStrictWithDistribute.$Default['distributive']]> extends true + ? IsStrictFunction._D + : SelectStrictWithDistribute._N + ) + : never : never + +export namespace IsStrictFunction { + export type $Options = SelectStrictWithDistribute.$Options + export type $Default = SelectStrictWithDistribute.$Default + export type $Branch = SelectStrictWithDistribute.$Branch + export type _D = + T extends Function + ? T extends (...args: any[]) => any + ? $ResolveSelection<$O, T, $Else> + : $ResolveSelection<$O, T, $Then> + : $ResolveSelection<$O, T, $Else> +} diff --git a/type-plus/ts/function/strict_function_type.is_not_strict_function.spec.ts b/type-plus/ts/function/strict_function_type.is_not_strict_function.spec.ts deleted file mode 100644 index df8362bc6e..0000000000 --- a/type-plus/ts/function/strict_function_type.is_not_strict_function.spec.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { it } from '@jest/globals' -import { testType, type AnyFunction, type IsNotStrictFunction } from '../index.js' - -it('returns false if T is Function', () => { - testType.false>(true) -}) - -it('returns true if T is function signature', () => { - testType.true void>>(true) - testType.true>(true) -}) - -it('returns true for special types', () => { - testType.true>(true) - testType.true>(true) - testType.true>(true) - testType.true>(true) -}) - -it('returns true for all other types', () => { - testType.true>(true) - testType.true>(true) - testType.true>(true) - testType.true>(true) - testType.true>(true) - testType.true>(true) - testType.true>(true) - testType.true>(true) - testType.true>(true) - testType.true>(true) - testType.true>(true) - testType.true>(true) - testType.true>(true) - testType.true>(true) - testType.true>(true) - testType.true>(true) -}) - -it('returns true if T is union of function and other types', () => { - testType.true>(true) -}) - -it('returns true if T is function overloads', () => { - testType.true>(true) -}) - -it('returns true if T is intersection of function', () => { - testType.true>(true) -}) - -it('can override Then/Else', () => { - testType.equal, 2>(true) - testType.equal, 1>(true) - - testType.equal, 1>(true) - testType.equal, 1>(true) - testType.equal, 1>(true) - testType.equal, 1>(true) -}) diff --git a/type-plus/ts/function/strict_function_type.is_strict_function.spec.ts b/type-plus/ts/function/strict_function_type.is_strict_function.spec.ts deleted file mode 100644 index 84d4299913..0000000000 --- a/type-plus/ts/function/strict_function_type.is_strict_function.spec.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { it } from '@jest/globals' -import { testType, type AnyFunction, type IsStrictFunction } from '../index.js' - -it('returns true if T is Function', () => { - testType.true>(true) -}) - -it('returns false if T is function signature', () => { - testType.false void>>(true) - testType.false>(true) -}) - -it('returns false for special types', () => { - testType.false>(true) - testType.false>(true) - testType.false>(true) - testType.false>(true) -}) - -it('returns false for all other types', () => { - testType.false>(true) - testType.false>(true) - testType.false>(true) - testType.false>(true) - testType.false>(true) - testType.false>(true) - testType.false>(true) - testType.false>(true) - testType.false>(true) - testType.false>(true) - testType.false>(true) - testType.false>(true) - testType.false>(true) - testType.false>(true) - testType.false>(true) - testType.false>(true) -}) - -it('returns false if T is union of function', () => { - testType.false>(true) -}) - -it('returns false if T is function overloads', () => { - testType.false>(true) -}) - -it('returns false if T is intersection of function', () => { - testType.false>(true) -}) - -it('can override Then/Else', () => { - testType.equal, 1>(true) - testType.equal, 2>(true) - - testType.equal, 2>(true) - testType.equal, 2>(true) - testType.equal, 2>(true) - testType.equal, 2>(true) -}) diff --git a/type-plus/ts/function/strict_function_type.not_strict_function_type.spec.ts b/type-plus/ts/function/strict_function_type.not_strict_function_type.spec.ts deleted file mode 100644 index a412a466d7..0000000000 --- a/type-plus/ts/function/strict_function_type.not_strict_function_type.spec.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { it } from '@jest/globals' -import { testType, type AnyFunction, type NotStrictFunctionType } from '../index.js' - -it('returns never if T is Function', () => { - testType.never>(true) -}) - -it('returns T if T is function signature', () => { - testType.equal void>, () => void>(true) - testType.equal, AnyFunction>(true) -}) - -it('returns T if T is function overloads', () => { - testType.equal, { (): void, (x: number): number }>( - true - ) -}) -it('returns T for special types', () => { - testType.equal, void>(true) - testType.equal, unknown>(true) - testType.equal, any>(true) - testType.equal, never>(true) -}) - -it('returns T for all other types', () => { - testType.equal, undefined>(true) - testType.equal, null>(true) - testType.equal, boolean>(true) - testType.equal, true>(true) - testType.equal, false>(true) - testType.equal, number>(true) - testType.equal, 1>(true) - testType.equal, string>(true) - testType.equal, ''>(true) - testType.equal, symbol>(true) - testType.equal, bigint>(true) - testType.equal, 1n>(true) - testType.equal, {}>(true) - testType.equal, { a: 1 }>(true) - testType.equal, string[]>(true) - testType.equal, []>(true) -}) - -it('returns T if T is union of function and other types', () => { - testType.equal, Function | { a: 1 }>(true) -}) - -it('returns T if T is intersection of function', () => { - testType.equal, Function & { a: 1 }>(true) -}) - -it('can override Then/Else', () => { - testType.equal, 2>(true) - testType.equal, 1>(true) - - testType.equal, 1>(true) - testType.equal, 1>(true) - testType.equal, 1>(true) - testType.equal, 1>(true) -}) diff --git a/type-plus/ts/function/strict_function_type.spec.ts b/type-plus/ts/function/strict_function_type.spec.ts deleted file mode 100644 index fa1a7e3ef3..0000000000 --- a/type-plus/ts/function/strict_function_type.spec.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { it } from '@jest/globals' -import { testType, type AnyFunction, type StrictFunctionType } from '../index.js' - -it('returns T if T is Function', () => { - testType.equal, Function>(true) -}) - -it('returns never if T is a function signature', () => { - testType.never void>>(true) - testType.never>(true) -}) - -it('returns never if T is function overloads', () => { - testType.never>(true) - testType.never>(true) -}) - -it('returns never for special types', () => { - testType.never>(true) - testType.never>(true) - testType.never>(true) - testType.never>(true) -}) - -it('returns never for other types', () => { - testType.never>(true) - testType.never>(true) - testType.never>(true) - testType.never>(true) - testType.never>(true) - testType.never>(true) - testType.never>(true) - testType.never>(true) - testType.never>(true) - testType.never>(true) - testType.never>(true) - testType.never>(true) - testType.never>(true) - testType.never>(true) - testType.never>(true) - testType.never>(true) -}) - -it('returns never if T is union of function and other types', () => { - testType.never>(true) -}) - -it('returns never if T is intersection of function', () => { - testType.never>(true) -}) - -it('can override Then/Else', () => { - testType.equal, 1>(true) - testType.equal, 2>(true) - - testType.equal, 2>(true) - testType.equal, 2>(true) - testType.equal, 2>(true) - testType.equal, 2>(true) -}) diff --git a/type-plus/ts/function/strict_function_type.ts b/type-plus/ts/function/strict_function_type.ts deleted file mode 100644 index 5afea4792d..0000000000 --- a/type-plus/ts/function/strict_function_type.ts +++ /dev/null @@ -1,55 +0,0 @@ -import type { IsAnyOrNever } from '../mix_types/is_any_or_never.js' -import type { $Else, $SelectionBranch, $Then } from '../type_plus/branch/selection.js' - -/** - * Check if `T` is exactly `Function`. - * - * ```ts - * type R = StrictFunctionType // Function - * - * type R = StrictFunctionType<() => void> // never - * type R = StrictFunctionType // never - * ``` - */ -export type StrictFunctionType = IsAnyOrNever< - T, - $SelectionBranch> extends infer R - ? R extends $Then ? Else - : R extends $Else ? [T, Function] extends [Function, T] ? Then : Else - : never : never - -/** - * Check if `T` is not exactly `Function`. - * - * ```ts - * type R = NotStrictFunctionType // never - * type R = NotStrictFunctionType<() => void> // () => void - * - * type R = NotStrictFunctionType // Function & { a: 1 } - * ``` - */ -export type NotStrictFunctionType = StrictFunctionType - -/** - * Is `T` exactly `Function`. - * - * ```ts - * type R = IsStrictFunction // true - * - * type R = IsStrictFunction<() => void> // false - * type R = IsStrictFunction<(() => void) & { a: 1 }> // false - * ``` - */ -export type IsStrictFunction = StrictFunctionType - -/** - * Is `T` not exactly `Function`. - * - * ```ts - * type R = IsNotStrictFunction // false - * - * type R = IsNotStrictFunction<() => void> // true - * type R = IsNotStrictFunction<(() => void) & { a: 1 }> // true - * ``` - */ -export type IsNotStrictFunction = StrictFunctionType diff --git a/type-plus/ts/index.ts b/type-plus/ts/index.ts index 548bf95430..9992e335bd 100644 --- a/type-plus/ts/index.ts +++ b/type-plus/ts/index.ts @@ -39,13 +39,10 @@ export type { ComposableTypes, NonComposableTypes } from './composable_types.js' export type { Equal, IsEqual, IsNotEqual, NotEqual } from './equal/equal.js' export type { AnyFunction } from './function/any_function.js' export * from './function/extract_function.js' -export type { FunctionType, IsFunction, IsNotFunction, NotFunctionType } from './function/function_type.js' -export type { - IsNotStrictFunction, - IsStrictFunction, - NotStrictFunctionType, - StrictFunctionType -} from './function/strict_function_type.js' +export type * from './function/is_function.js' +export type * from './function/is_not_function.js' +export type * from './function/is_not_strict_function.js' +export type * from './function/is_strict_function.js' export * from './functional/index.js' export type { JSONArray, JSONObject, JSONPrimitive, JSONTypes } from './json.js' export type { Abs, Add, Decrement, GreaterThan, Increment, Max, Multiply, Subtract } from './math/index.js' diff --git a/type-plus/ts/mix_types/box.ts b/type-plus/ts/mix_types/box.ts index db1f513901..415272251f 100644 --- a/type-plus/ts/mix_types/box.ts +++ b/type-plus/ts/mix_types/box.ts @@ -1,6 +1,6 @@ import type { IsBigint } from '../bigint/is_bigint.js' import type { IsBoolean } from '../boolean/is_boolean.js' -import type { IsFunction } from '../function/function_type.js' +import type { IsFunction } from '../function/is_function.js' import type { IsNumber } from '../number/is_number.js' import type { IsStrictObject } from '../object/is_strict_object.js' import type { IsString } from '../string/string_type.js' @@ -28,34 +28,36 @@ import type { $Else, $SelectionBranch, $Then } from '../type_plus/branch/selecti export type Box = IsFunction< T, - Function, - IsStrictObject< + IsFunction.$Branch + > extends infer R + ? R extends $Then ? Function + : IsStrictObject< + T, + Object, + T extends Record ? T : + IsBoolean< T, - Object, - T extends Record ? T : - IsBoolean< - T, - $SelectionBranch - > extends infer R - ? R extends $Then ? Boolean - : R extends $Else ? IsNumber< - T, - IsNumber.$Branch - > extends infer R - ? R extends $Then ? Number - : R extends $Else ? IsString< + $SelectionBranch + > extends infer R + ? R extends $Then ? Boolean + : R extends $Else ? IsNumber< + T, + IsNumber.$Branch + > extends infer R + ? R extends $Then ? Number + : R extends $Else ? IsString< + T, + String, + IsSymbol< T, - String, - IsSymbol< - T, - Symbol, - IsBigint - > + Symbol, + IsBigint > - : never : never - : never : never > + : never : never + : never : never > + : never export namespace Box { export type Options = { diff --git a/type-plus/ts/type_plus/branch/select_invert_strict_with_distribute.ts b/type-plus/ts/type_plus/branch/select_invert_strict_with_distribute.ts index 0f1e62e565..b3889f1c42 100644 --- a/type-plus/ts/type_plus/branch/select_invert_strict_with_distribute.ts +++ b/type-plus/ts/type_plus/branch/select_invert_strict_with_distribute.ts @@ -65,10 +65,8 @@ export type SelectInvertStrictWithDistribute< ? R extends $Then ? $ResolveSelection<$O, T, $Then> : R extends $Else ? ( $ResolveOptions<[$O['distributive'], SelectInvertStrictWithDistribute.$Default['distributive']]> extends true - // ? (T extends U ? $ResolveSelection<$O, T, $Else> : - // U extends T ? $ResolveSelection<$O, T, $Else> : $ResolveSelection<$O, T, $Then>) - ? [T, U] extends [U, T] ? $ResolveSelection<$O, T, $Else> : $ResolveSelection<$O, T, $Then> - : [T, U] extends [U, T] ? $ResolveSelection<$O, T, $Else> : $ResolveSelection<$O, T, $Then> + ? SelectInvertStrictWithDistribute._D + : SelectInvertStrictWithDistribute._N ) : never : never @@ -76,4 +74,13 @@ export namespace SelectInvertStrictWithDistribute { export type $Options = $SelectionOptions & $DistributiveOptions export type $Default = $SelectionPredicate & $DistributiveDefault export type $Branch = $SelectionBranch & $DistributiveDefault + export type _D = + T extends U ? $ResolveSelection<$O, T, $Else> + : $ResolveSelection<$O, T, $Then> + // T extends U ? U extends T + // ? $ResolveSelection<$O, T, $Else> + // : $ResolveSelection<$O, T, $Then> + // : $ResolveSelection<$O, T, $Then> + export type _N = + [T, U] extends [U, T] ? $ResolveSelection<$O, T, $Else> : $ResolveSelection<$O, T, $Then> } diff --git a/type-plus/ts/type_plus/branch/select_strict_with_distribute.ts b/type-plus/ts/type_plus/branch/select_strict_with_distribute.ts new file mode 100644 index 0000000000..51e54c2b43 --- /dev/null +++ b/type-plus/ts/type_plus/branch/select_strict_with_distribute.ts @@ -0,0 +1,84 @@ +import type { IsAnyOrNever } from '../../mix_types/is_any_or_never.js' +import type { $ResolveOptions } from '../resolve_options.js' +import type { $DistributiveDefault, $DistributiveOptions } from './distributive.js' +import type { $Else, $ResolveSelection, $SelectionBranch, $SelectionOptions, $SelectionPredicate, $Then } from './selection.js' + +/** + * 🎭 *predicate* + * ㊙️ *internal* + * + * Validate if `T` is `U`. + * + * @example + * ```ts + * type R = SelectStrictWithDistribute // true + * + * type R = SelectStrictWithDistribute // false + * type R = SelectStrictWithDistribute // false + * type R = SelectStrictWithDistribute // false + * + * type R = SelectStrictWithDistribute // boolean + * ``` + * + * 🔢 *customize* + * + * Filter to ensure `T` is `U`, otherwise returns `never`. + * + * @example + * ```ts + * type R = SelectStrictWithDistribute // undefined + * + * type R = SelectStrictWithDistribute // never + * type R = SelectStrictWithDistribute // never + * type R = SelectStrictWithDistribute // never + * + * type R = SelectStrictWithDistribute // undefined + * ``` + * + * 🔢 *customize*: + * + * Disable distribution of union types. + * + * ```ts + * type R = SelectStrictWithDistribute // boolean + * type R = SelectStrictWithDistribute // false + * ``` + * + * 🔢 *customize* + * + * Use unique branch identifiers to allow precise processing of the result. + * + * @example + * ```ts + * type R = SelectStrictWithDistribute // $Then + * type R = SelectStrictWithDistribute // $Else + * ``` + */ +export type SelectStrictWithDistribute< + T, + U, + $O extends SelectStrictWithDistribute.$Options = {} +> = IsAnyOrNever< + T, + $SelectionBranch +> extends infer R + ? R extends $Then ? $ResolveSelection<$O, T, $Else> + : R extends $Else ? ( + $ResolveOptions<[$O['distributive'], SelectStrictWithDistribute.$Default['distributive']]> extends true + ? SelectStrictWithDistribute._D + : SelectStrictWithDistribute._N + ) + : never : never + +export namespace SelectStrictWithDistribute { + export type $Options = $SelectionOptions & $DistributiveOptions + export type $Default = $SelectionPredicate & $DistributiveDefault + export type $Branch = $SelectionBranch & $DistributiveDefault + export type _D = + T extends U ? U extends T + ? $ResolveSelection<$O, T, $Then> + : $ResolveSelection<$O, T, $Else> + : $ResolveSelection<$O, T, $Else> + export type _N = + [T, U] extends [U, T] ? $ResolveSelection<$O, T, $Then> : $ResolveSelection<$O, T, $Else> +}