From e61d38d9b6b5bf1a659d0ffdd4b685d751ec0abf Mon Sep 17 00:00:00 2001 From: unional Date: Sun, 24 Sep 2023 01:58:39 -0700 Subject: [PATCH] feat: merge NeverType to IsNever --- type-plus/ts/any/is_any.ts | 12 ++- type-plus/ts/any/is_not_any.ts | 20 ++++- type-plus/ts/any/readme.md | 92 ++++++--------------- type-plus/ts/index.ts | 2 - type-plus/ts/never/is_never.spec.ts | 45 ++++++++++- type-plus/ts/never/is_never.ts | 55 +++++++++++-- type-plus/ts/never/is_not_never.spec.ts | 42 +++++++++- type-plus/ts/never/is_not_never.ts | 58 +++++++++++-- type-plus/ts/never/never_type.spec.ts | 55 ------------- type-plus/ts/never/never_type.ts | 36 --------- type-plus/ts/never/not_never_type.spec.ts | 47 ----------- type-plus/ts/never/not_never_type.ts | 37 --------- type-plus/ts/never/readme.md | 94 +++++++++++++--------- type-plus/ts/object/merge.ts | 32 +++++--- type-plus/ts/type_plus/branch/selection.ts | 1 + 15 files changed, 312 insertions(+), 316 deletions(-) delete mode 100644 type-plus/ts/never/never_type.spec.ts delete mode 100644 type-plus/ts/never/never_type.ts delete mode 100644 type-plus/ts/never/not_never_type.spec.ts delete mode 100644 type-plus/ts/never/not_never_type.ts diff --git a/type-plus/ts/any/is_any.ts b/type-plus/ts/any/is_any.ts index 2e1e5637fd..80cf2f7e93 100644 --- a/type-plus/ts/any/is_any.ts +++ b/type-plus/ts/any/is_any.ts @@ -2,10 +2,10 @@ import type { $Else, $ResolveSelection, $SelectionOptions, $Then } from '../type /** * 🎭 *predicate* - * 🔢 *customize* * * Validate if `T` is exactly `any`. * + * @example * ```ts * type R = IsAny // true * @@ -14,8 +14,11 @@ import type { $Else, $ResolveSelection, $SelectionOptions, $Then } from '../type * type R = IsAny // false * ``` * - * 🔢 *customize*: filter + * 🔢 *customize* + * + * Filter to ensure `T` is exactly `any`. * + * @example * ```ts * type R = IsAny // any * @@ -24,8 +27,11 @@ import type { $Else, $ResolveSelection, $SelectionOptions, $Then } from '../type * type R = IsAny // never * ``` * - * 🔢 *customize*: branching + * 🔢 *customize* + * + * Use unique branch identifiers to allow precise processing of the result. * + * @example * ```ts * type R = IsAny // $Then * type R = IsAny // $Else diff --git a/type-plus/ts/any/is_not_any.ts b/type-plus/ts/any/is_not_any.ts index fff7b71bde..13809ce3cc 100644 --- a/type-plus/ts/any/is_not_any.ts +++ b/type-plus/ts/any/is_not_any.ts @@ -3,10 +3,10 @@ import type { IsAny } from './is_any.js' /** * 🎭 *predicate* - * 🔢 *customize* * * Validate if `T` is not exactly `any`. * + * @example * ```ts * type R = IsNotAny // false * @@ -15,8 +15,24 @@ import type { IsAny } from './is_any.js' * type R = IsNotAny // true * ``` * - * 🔢 *customize*: branching + * 🔢 *customize* + * + * Filter to ensure `T` is not exactly `any`. + * + * @example + * ```ts + * type R = IsNotAny // never + * + * type R = IsNotAny // never + * type R = IsNotAny // unknown + * type R = IsNotAny // string | boolean + * ``` + * + * 🔢 *customize* + * + * Use unique branch identifiers to allow precise processing of the result. * + * @example * ```ts * type R = IsNotAny // $Else * type R = IsNotAny // $Then diff --git a/type-plus/ts/any/readme.md b/type-plus/ts/any/readme.md index 627c60062f..901a7d2f32 100644 --- a/type-plus/ts/any/readme.md +++ b/type-plus/ts/any/readme.md @@ -4,74 +4,11 @@ It is a supertype of all types. It is a way to opt-out of type checking and let the values pass through compile-time checks. -## [AnyType](./any_type.ts) - -`AnyType` - -🌪️ *filter* -🔢 *customize* - -Filter to ensure `T` is exactly `any`. - -```ts -type R = AnyType // any - -type R = AnyType // never -type R = AnyType // never -type R = AnyType // never -``` - -🔢 *customize*: as predicate/validate (= `IsAny`) - -```ts -type R = AnyType // true -type R = AnyType // false -``` - -🔢 *customize*: branching - -```ts -type R = AnyType // $Then -type R = AnyType // $Else -``` - -## [NotAnyType](./not_any_type.ts) - -`NotAnyType` - -🌪️ *filter* -🔢 *customize* - -Filter to ensure `T` is not exactly `any`. - -```ts -type R = NotAnyType // never - -type R = NotAnyType // never -type R = NotAnyType // unknown -type R = NotAnyType // string | boolean -``` - -🔢 *customize*: as predicate/validate (= `IsNotAny`) - -```ts -type R = NotAnyType // true -type R = NotAnyType // false -``` - -🔢 *customize*: branching - -```ts -type R = NotAnyType // $Then -type R = NotAnyType // $Else -``` - ## [IsAny](./is_any.ts) -`IsAny` +`IsAny` 🎭 *predicate* -🔢 *customize* Validate if `T` is exactly `any`. @@ -83,7 +20,9 @@ type R = IsAny // false type R = IsAny // false ``` -🔢 *customize*: filter +🔢 *customize* + +Filter to ensure `T` is exactly `any`. ```ts type R = IsAny // any @@ -93,7 +32,9 @@ type R = IsAny // never type R = IsAny // never ``` -🔢 *customize*: branching +🔢 *customize* + +Use unique branch identifiers to allow precise processing of the result. ```ts type R = IsAny // $Then @@ -102,10 +43,9 @@ type R = IsAny // $Else ### [IsNotAny](./is_not_any.ts) -`IsNotAny` +`IsNotAny` 🎭 *predicate* -🔢 *customize* Validate if `T` is not exactly `any`. @@ -117,7 +57,21 @@ type R = IsNotAny // true type R = IsNotAny // true ``` -🔢 *customize*: branching +🔢 *customize* + +Filter to ensure `T` is not exactly `any`. + +```ts +type R = IsNotAny // never + +type R = IsNotAny // never +type R = IsNotAny // unknown +type R = IsNotAny // string | boolean +``` + +🔢 *customize* + +Use unique branch identifiers to allow precise processing of the result. ```ts type R = IsNotAny // $Else diff --git a/type-plus/ts/index.ts b/type-plus/ts/index.ts index 856948e8e9..7435516b73 100644 --- a/type-plus/ts/index.ts +++ b/type-plus/ts/index.ts @@ -63,8 +63,6 @@ export * from './mix_types/merge.js' export type * from './never/is_never.js' export type * from './never/is_not_never.js' export type * from './never/never.js' -export type * from './never/never_type.js' -export type * from './never/not_never_type.js' export * from './nodejs/index.js' export * from './nominal/index.js' export type * from './null/non_null.js' diff --git a/type-plus/ts/never/is_never.spec.ts b/type-plus/ts/never/is_never.spec.ts index 863b2230b3..cd056ca491 100644 --- a/type-plus/ts/never/is_never.spec.ts +++ b/type-plus/ts/never/is_never.spec.ts @@ -1,6 +1,7 @@ import { it } from '@jest/globals' // never intersect with any type is never -import { testType, type IsNever } from '../index.js' +import { describe } from 'node:test' +import { testType, type $NotNever, type IsNever } from '../index.js' it('returns true for never', () => { testType.true>(true) @@ -48,3 +49,45 @@ it('can override Then/Else', () => { testType.equal, 2>(true) testType.equal, 2>(true) }) + +describe('filter', () => { + + it('returns never if T is never', () => { + testType.equal, never>(true) + }) + + it('returns $NotNever for other special types', () => { + testType.equal, $NotNever>(true) + testType.equal, $NotNever>(true) + testType.equal, $NotNever>(true) + }) + + it('returns $NotNever for other types', () => { + testType.equal, $NotNever>(true) + testType.equal, $NotNever>(true) + testType.equal, $NotNever>(true) + testType.equal, $NotNever>(true) + testType.equal, $NotNever>(true) + testType.equal, $NotNever>(true) + testType.equal, $NotNever>(true) + testType.equal, $NotNever>(true) + testType.equal, $NotNever>(true) + testType.equal, $NotNever>(true) + testType.equal, $NotNever>(true) + testType.equal, $NotNever>(true) + testType.equal, $NotNever>(true) + testType.equal, $NotNever>(true) + testType.equal void, { selection: 'filter' }>, $NotNever>(true) + }) + + it('returns $NotNever for union type', () => { + testType.equal, $NotNever>(true) + }) + + it('returns never for intersection type', () => { + // TypeScript resolve this to `never` automatically, + // so `IsNever<>` actually does not do anthing in this case. + testType.never(true) + testType.never>(true) + }) +}) diff --git a/type-plus/ts/never/is_never.ts b/type-plus/ts/never/is_never.ts index 19e981b0d4..025cdb68f5 100644 --- a/type-plus/ts/never/is_never.ts +++ b/type-plus/ts/never/is_never.ts @@ -1,20 +1,48 @@ -import type { $SelectionOptions, $SelectionPredicate } from '../type_plus/branch/selection.js' +import type { $SelectionOptions } from '../type_plus/branch/selection.js' import type { $ResolveOptions } from '../type_plus/resolve_options.js' +import type { $NotNever } from './never.js' /** * 🎭 *predicate* - * 🔢 *customize* * * Validate if `T` is `never`. * + * @example * ```ts * type R = IsNever // true * * type R = IsNever<1> // false * ``` * - * 🔢 *customize*: branching + * 🔢 *customize* + * + * Filter to ensure `T` is `never`, otherwise returns `$NotNever`. + * + * Filter normally returns `never` in the `$else` clause. + * But since we are checking for `never` here, + * we have to return `$NotNever` instead. + * + * @example + * ```ts + * type R = IsNever // never + * + * type R = IsNever<1, { selection: 'filter' }> // $NotNever + * ``` + * + * 🔢 *customize* + * + * Filter to ensure `T` is `never`, otherwise returns `unknown`. * + * @example + * ```ts + * type R = IsNever<1, { selection: 'filter-unknown' }> // unknown + * ``` + * + * 🔢 *customize* + * + * Use unique branch identifiers to allow precise processing of the result. + * + * @example * ```ts * type R = IsNever // $Then * type R = IsNever<1, $SelectionBranch> // $Else @@ -22,8 +50,23 @@ import type { $ResolveOptions } from '../type_plus/resolve_options.js' */ export type IsNever< T, - $O extends $SelectionOptions = $SelectionPredicate + $O extends IsNever.$Options = {} > = [T, never] extends [never, T] - ? $ResolveOptions<[$O['$then'], true]> - : $ResolveOptions<[$O['$else'], false]> + ? $ResolveOptions<[$O['$then'], $O['selection'] extends 'filter' | 'filter-unknown' ? T : true]> + : $ResolveOptions<[$O['$else'], $O['selection'] extends 'filter' + ? $NotNever + : $O['selection'] extends 'filter-unknown' ? unknown : false]> + +export namespace IsNever { + export type $Options = Omit<$SelectionOptions, 'selection'> & { + /** + * On top of `selection` values from `$SelectionOptions`, + * + * it also support: + * + * `filter-unknown` which returns `unknown` when `T` is `never` + */ + selection?: 'predicate' | 'filter' | 'filter-unknown' | undefined + } +} diff --git a/type-plus/ts/never/is_not_never.spec.ts b/type-plus/ts/never/is_not_never.spec.ts index cdfb19ccb7..0b64452d93 100644 --- a/type-plus/ts/never/is_not_never.spec.ts +++ b/type-plus/ts/never/is_not_never.spec.ts @@ -1,5 +1,6 @@ import { it } from '@jest/globals' -import { testType, type IsNotNever } from '../index.js' +import { testType, type IsNotNever, type $Never } from '../index.js' +import { describe } from 'node:test' it('returns false for never', () => { testType.false>(true) @@ -47,3 +48,42 @@ it('can override Then/Else', () => { testType.equal, 1>(true) testType.equal, 1>(true) }) + +describe('filter', () => { + + it('returns `is_never` if T is never', () => { + testType.equal, $Never>(true) + }) + + it('returns T for other special types', () => { + testType.equal, unknown>(true) + testType.equal, void>(true) + testType.equal, any>(true) + }) + + it('returns T for other types', () => { + testType.equal, undefined>(true) + testType.equal, null>(true) + testType.equal, number>(true) + testType.equal, boolean>(true) + testType.equal, true>(true) + testType.equal, false>(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) + testType.equal, Function>(true) + testType.equal void, { selection: 'filter' }>, () => void>(true) + }) + + it('returns T for union type', () => { + testType.equal, 1>(true) + }) + + it('returns $Never for intersection type', () => { + testType.equal, $Never>(true) + }) +}) diff --git a/type-plus/ts/never/is_not_never.ts b/type-plus/ts/never/is_not_never.ts index aac00f2e6c..3f61a11837 100644 --- a/type-plus/ts/never/is_not_never.ts +++ b/type-plus/ts/never/is_not_never.ts @@ -1,20 +1,48 @@ -import type { $FlipSelection, $SelectionOptions, $SelectionPredicate } from '../type_plus/branch/selection.js' -import type { IsNever } from './is_never.js' +import type { $SelectionOptions } from '../type_plus/branch/selection.js' +import type { $ResolveOptions } from '../type_plus/resolve_options.js' +import type { $Never } from './never.js' /** * 🎭 *predicate* - * 🔢 *customize* * * Validate if `T` not `never`. * + * @example * ```ts * type R = IsNotNever<1> // true * * type R = IsNotNever // false * ``` * - * 🔢 *customize*: branching + * 🔢 *customize* + * + * Filter to ensure `T` is not `never`, otherwise returns `$Never`. * + * Filter normally returns `never` in the `$else` clause. + * But since we are checking for `never` here, + * we have to return `$Never` instead. + * + * @example + * ```ts + * type R = IsNotNever<1, { selection: 'filter' }> // 1 + * + * type R = IsNotNever // $Never + * ``` + * + * 🔢 *customize* + * + * Filter to ensure `T` is `never`, otherwise returns `unknown`. + * + * @example + * ```ts + * type R = IsNotNever // unknown + * ``` + * + * 🔢 *customize* + * + * Use unique branch identifiers to allow precise processing of the result. + * + * @example * ```ts * type R = IsNotNever // $Else * type R = IsNotNever<1, $SelectionBranch> // $Then @@ -22,5 +50,23 @@ import type { IsNever } from './is_never.js' */ export type IsNotNever< T, - $Options extends $SelectionOptions = $SelectionPredicate -> = IsNever> + $O extends IsNotNever.$Options = {} +> = [T, never] extends [never, T] + ? $ResolveOptions<[$O['$else'], $O['selection'] extends 'filter' + ? $Never + : $O['selection'] extends 'filter-unknown' ? unknown : false]> + : $ResolveOptions<[$O['$then'], $O['selection'] extends 'filter' | 'filter-unknown' ? T : true]> + + +export namespace IsNotNever { + export type $Options = Omit<$SelectionOptions, 'selection'> & { + /** + * On top of `selection` values from `$SelectionOptions`, + * + * it also support: + * + * `filter-unknown` which returns `unknown` when `T` is `never` + */ + selection?: 'predicate' | 'filter' | 'filter-unknown' | undefined + } +} diff --git a/type-plus/ts/never/never_type.spec.ts b/type-plus/ts/never/never_type.spec.ts deleted file mode 100644 index ef747dc2b3..0000000000 --- a/type-plus/ts/never/never_type.spec.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { it } from '@jest/globals' -import { testType, type $NotNever, type NeverType } from '../index.js' - -it('returns never if T is never', () => { - testType.equal, never>(true) -}) - -it('returns $NotNever for other special types', () => { - testType.equal, $NotNever>(true) - testType.equal, $NotNever>(true) - testType.equal, $NotNever>(true) -}) - -it('returns $NotNever for other types', () => { - testType.equal, $NotNever>(true) - testType.equal, $NotNever>(true) - testType.equal, $NotNever>(true) - testType.equal, $NotNever>(true) - testType.equal, $NotNever>(true) - testType.equal, $NotNever>(true) - testType.equal, $NotNever>(true) - testType.equal, $NotNever>(true) - testType.equal, $NotNever>(true) - testType.equal, $NotNever>(true) - testType.equal, $NotNever>(true) - testType.equal, $NotNever>(true) - testType.equal, $NotNever>(true) - testType.equal, $NotNever>(true) - testType.equal void>, $NotNever>(true) -}) - -it('returns $NotNever for union type', () => { - testType.equal, $NotNever>(true) -}) - -it('returns never for intersection type', () => { - // TypeScript resolve this to `never` automatically, - // so `NeverType<>` actually does not do anthing in this case. - testType.never(true) - 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) -}) - -it('supports partial customization', () => { - testType.equal, never>(true) - testType.equal, $NotNever>(true) -}) diff --git a/type-plus/ts/never/never_type.ts b/type-plus/ts/never/never_type.ts deleted file mode 100644 index 025a2ec74f..0000000000 --- a/type-plus/ts/never/never_type.ts +++ /dev/null @@ -1,36 +0,0 @@ -import type { $SelectionOptions } from '../type_plus/branch/selection.js' -import type { $ResolveOptions } from '../type_plus/resolve_options.js' -import type { $NotNever } from './never.js' - -/** - * 🌪️ *filter* - * 🔢 *customize* - * - * Filter to ensure `T` is `never`, otherwise returns `$NotNever`. - * - * ```ts - * type R = NeverType // never - * - * type R = NeverType<1> // $NotNever - * ``` - * - * 🔢 *customize*: as predicate/validate (= `IsNever`) - * - * ```ts - * type R = NeverType // true - * type R = NeverType<1, $SelectionPredicate> // false - * ``` - * - * 🔢 *customize*: branching - * - * ```ts - * type R = NeverType // $Then - * type R = NeverType<1, $SelectionBranch> // $Else - * ``` - */ -export type NeverType< - T, - $O extends $SelectionOptions = { $then: T, $else: $NotNever } -> = [T, never] extends [never, T] -? $ResolveOptions<[$O['$then'], T]> -: $ResolveOptions<[$O['$else'], $NotNever]> diff --git a/type-plus/ts/never/not_never_type.spec.ts b/type-plus/ts/never/not_never_type.spec.ts deleted file mode 100644 index 7cec16dde5..0000000000 --- a/type-plus/ts/never/not_never_type.spec.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { it } from '@jest/globals' -import { testType, type $Never, type NotNeverType } from '../index.js' - -it('returns `is_never` if T is never', () => { - testType.equal, $Never>(true) -}) - -it('returns T for other special types', () => { - testType.equal, unknown>(true) - testType.equal, void>(true) - testType.equal, any>(true) -}) - -it('returns T for other types', () => { - testType.equal, undefined>(true) - testType.equal, null>(true) - testType.equal, number>(true) - testType.equal, boolean>(true) - testType.equal, true>(true) - testType.equal, false>(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) - testType.equal, Function>(true) - testType.equal void>, () => void>(true) -}) - -it('returns T for union type', () => { - testType.equal, 1>(true) -}) - -it('returns $Never for intersection type', () => { - testType.equal, $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) -}) diff --git a/type-plus/ts/never/not_never_type.ts b/type-plus/ts/never/not_never_type.ts deleted file mode 100644 index 461af073e1..0000000000 --- a/type-plus/ts/never/not_never_type.ts +++ /dev/null @@ -1,37 +0,0 @@ -import type { $Else, $SelectionBranch, $SelectionOptions, $Then } from '../type_plus/branch/selection.js' -import type { IsNever } from './is_never.js' -import type { $Never } from './never.js' - -/** - * 🌪️ *filter* - * 🔢 *customize* - * - * Filter to ensure `T` is not `never`, otherwise returns `$Never`. - * - * ```ts - * type R = NotNeverType<1> // 1 - * - * type R = NotNeverType // $Never - * ``` - * - * 🔢 *customize*: as predicate/validate (= `IsNotNever`) - * - * ```ts - * type R = NotNeverType<1, $SelectionPredicate> // true - * type R = NotNeverType // false - * ``` - * - * 🔢 *customize*: branching - * - * ```ts - * type R = NotNeverType // $Else - * type R = NotNeverType<1, $SelectionBranch> // $Then - * ``` - */ -export type NotNeverType< - T, - $Options extends $SelectionOptions = { $then: T, $else: $Never } -> = IsNever extends infer R - ? R extends $Then ? $Options['$else'] - : R extends $Else ? $Options['$then'] - : never : never diff --git a/type-plus/ts/never/readme.md b/type-plus/ts/never/readme.md index 774d697fec..592cd7eaaf 100644 --- a/type-plus/ts/never/readme.md +++ b/type-plus/ts/never/readme.md @@ -3,87 +3,101 @@ `never` is a bottom type in TypeScript. That means it is a subtype of all other types. -## Type Checking +## [IsNever](./is_never.ts) -The `NeverType` and friends are used to check if a type is exactly `never`. +`IsNever` -Filter normally returns `never` in the `$else` clause. -But since we are checking for `never` here, -they have to return something other than `never`. +🎭 *predicate* -Therefore, `NeverType` will return the `$NotNever` when `T` is not `never`, -and `NotNeverType` will return the `$Never` symbol when `T` is `never`. +Validate if `T` is `never`. -### [NeverType](./never_type.ts) +```ts +type R = IsNever // true -`NeverType` +type R = IsNever<1> // false +``` -🌪️ *filter* 🔢 *customize* -Filter to ensure `T` is exactly `never`. +Filter to ensure `T` is `never`, otherwise returns `$NotNever`. -If it is not, returns `$NotNever`. +Filter normally returns `never` in the `$else` clause. +But since we are checking for `never` here, +we have to return `$NotNever` instead. ```ts -import type { NeverType } from 'type-plus' - -type R = NeverType // never +type R = IsNever // never -type R = NeverType // $NotNever -type R = NeverType // $NotNever +type R = IsNever<1, { selection: 'filter' }> // $NotNever ``` -### [IsNever](./is_never.ts) +🔢 *customize* -`IsNever` +Filter to ensure `T` is `never`, otherwise returns `unknown`. + +```ts +type R = IsNever<1, { selection: 'filter-unknown' }> // unknown +``` -🎭 *predicate* 🔢 *customize* -Validate if `T` is exactly `never`. +Use unique branch identifiers to allow precise processing of the result. ```ts -import type { IsNever } from 'type-plus' +type R = IsNever // $Then +type R = IsNever<1, $SelectionBranch> // $Else +``` -type R = IsNever // true +### [IsNotNever](./is_not_never.ts) -type R = IsNever // false -type R = IsNever // false -``` +`IsNotNever` -### [NotNeverType](./not_never_type.ts) +🎭 *predicate* + +Validate if `T` not `never`. -`NotNeverType` +```ts +type R = IsNotNever<1> // true + +type R = IsNotNever // false +``` -🌪️ *filter* 🔢 *customize* -Filter `T` to ensure it is not exactly `never`. +Filter to ensure `T` is not `never`, otherwise returns `$Never`. -### [IsNotNever](./is_not_never.ts) +Filter normally returns `never` in the `$else` clause. +But since we are checking for `never` here, +we have to return `$Never` instead. -`IsNotNever` +```ts +type R = IsNotNever<1, { selection: 'filter' }> // 1 + +type R = IsNotNever // $Never +``` -🎭 *predicate* 🔢 *customize* -Validate if `T` is not exactly `never`. +Filter to ensure `T` is `never`, otherwise returns `unknown`. ```ts -import type { IsNotNever } from 'type-plus' +type R = IsNotNever // unknown +``` -type R = IsNotNever // true -type R = IsNotNever // true +🔢 *customize* -type R = IsNotNever // false +Use unique branch identifiers to allow precise processing of the result. + +```ts +type R = IsNotNever // $Else +type R = IsNotNever<1, $SelectionBranch> // $Then ``` ## [$Never](./never.ts) `$Never` is a special branch type to indicate the type is `never`. -It is used in [`NotNeverType`](#notnevertype). +It is used in [`IsNotNever`](#isnotnever). ## [$NeverOptions](./never.ts) @@ -139,7 +153,7 @@ Unsurprisingly, defaulting `$never` to `never`. `$NotNever` is a special branch type to indicate the type is not `never`. -It is used in [`NeverType`](#nevertype). +It is used in [`IsNever`](#isnever). ## References diff --git a/type-plus/ts/object/merge.ts b/type-plus/ts/object/merge.ts index 91f1351aa4..3f1d28ded6 100644 --- a/type-plus/ts/object/merge.ts +++ b/type-plus/ts/object/merge.ts @@ -1,8 +1,8 @@ import type { IsAny } from '../any/is_any.js' import type { NonComposableTypes } from '../composable_types.js' import type { IsNever } from '../never/is_never.js' +import type { IsNotNever } from '../never/is_not_never.js' import type { $Never } from '../never/never.js' -import type { NotNeverType } from '../never/not_never_type.js' import type { IsLiteral } from '../predicates/literal.js' import type { Or } from '../predicates/logical.js' import type { IsDisjoint } from './IsDisjoint.js' @@ -37,56 +37,63 @@ export type Merge, OptionalKeys] extends [infer PKA extends KeyTypes, infer PKB extends KeyTypes] ? // property is optional when both A[k] and B[k] are optional - NotNeverType< + IsNotNever< PKA & PKB, { + selection: 'filter-unknown', $then: { [k in PKA & PKB]?: A[k] | B[k] }, $else: unknown } > & // properties only in A excluding partials is A[k] - NotNeverType< + IsNotNever< Exclude, { + selection: 'filter-unknown', $then: { [k in Exclude]: A[k] }, $else: unknown } > & // properties only in B excluding partials is B[k] - NotNeverType< + IsNotNever< Exclude, { + selection: 'filter-unknown', $then: { [k in Exclude]: B[k] }, $else: unknown } > & // properties is required in A but optional in B is unionized without undefined - NotNeverType< + IsNotNever< Exclude, { + selection: 'filter-unknown', $then: { [k in Exclude]: A[k] | Exclude }, $else: unknown } > : never) : - NotNeverType< + IsNotNever< Exclude, { + selection: 'filter-unknown', $then: { [k in Exclude]: A[k] }, $else: unknown } > & - NotNeverType< + IsNotNever< Exclude, { + selection: 'filter-unknown', $then: { [k in Exclude]: B[k] }, $else: unknown } > & - NotNeverType< + IsNotNever< KA & KB, { + selection: 'filter-unknown', $then: { [k in KA & KB]: A[k] | B[k] }, $else: unknown } @@ -96,23 +103,26 @@ export type Merge extends true ? { [k in Exclude]: A[k] } & { [k in keyof B]: B[k] } : - NotNeverType< + IsNotNever< Exclude, { + selection: 'filter-unknown', $then: { [k in Exclude]: A[k] }, $else: unknown } > & - NotNeverType< + IsNotNever< Exclude, { + selection: 'filter-unknown', $then: { [k in Exclude]: B[k] }, $else: unknown } > & - NotNeverType< + IsNotNever< KA & KB, { + selection: 'filter-unknown', $then: { [k in KA & KB]: A[k] | B[k] }, $else: unknown } diff --git a/type-plus/ts/type_plus/branch/selection.ts b/type-plus/ts/type_plus/branch/selection.ts index 49cb7385fc..8c8cbec1d4 100644 --- a/type-plus/ts/type_plus/branch/selection.ts +++ b/type-plus/ts/type_plus/branch/selection.ts @@ -63,6 +63,7 @@ export type $InvertSelection = * * This encourage consumer of your type to use conditional type to avoid performance issues. * + * @example * ```ts * type YourType< * T,