Skip to content

Commit

Permalink
feat: update is boolean types
Browse files Browse the repository at this point in the history
  • Loading branch information
unional committed Oct 1, 2023
1 parent 03af9f1 commit 53440e5
Show file tree
Hide file tree
Showing 20 changed files with 600 additions and 303 deletions.
35 changes: 24 additions & 11 deletions type-plus/ts/boolean/is_boolean.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { it } from '@jest/globals'
import { testType, type IsBoolean } from '../index.js'
import { testType, type IsBoolean, type $Then, type $Else } from '../index.js'

it('returns true if T is boolean', () => {
testType.true<IsBoolean<boolean>>(true)
Expand Down Expand Up @@ -35,21 +35,34 @@ it('returns false for other types', () => {
testType.false<IsBoolean<() => void>>(true)
})

it('returns false for union type', () => {
testType.false<IsBoolean<boolean | 1>>(true)
it('distributes over union type', () => {
testType.equal<IsBoolean<boolean | 1>, boolean>(true)
})

it('can disable union distribution', () => {
testType.false<IsBoolean<boolean | 1, { distributive: false }>>(true)
})

it('returns true for intersection type', () => {
testType.true<IsBoolean<boolean & { a: 1 }>>(true)
})

it('can override Then/Else', () => {
testType.equal<IsBoolean<boolean, 1, 2>, 1>(true)
testType.equal<IsBoolean<true, 1, 2>, 1>(true)
testType.equal<IsBoolean<false, 1, 2>, 1>(true)
it('works as filter', () => {
testType.equal<IsBoolean<boolean, { selection: 'filter' }>, boolean>(true)
testType.equal<IsBoolean<true, { selection: 'filter' }>, true>(true)

testType.equal<IsBoolean<never, { selection: 'filter' }>, never>(true)
testType.equal<IsBoolean<unknown, { selection: 'filter' }>, never>(true)
testType.equal<IsBoolean<string | boolean, { selection: 'filter' }>, boolean>(true)

testType.equal<IsBoolean<string | true, { selection: 'filter' }>, true>(true)
})

it('works with unique branches', () => {
testType.equal<IsBoolean<boolean, IsBoolean.$Branch>, $Then>(true)

testType.equal<IsBoolean<any, 1, 2>, 2>(true)
testType.equal<IsBoolean<unknown, 1, 2>, 2>(true)
testType.equal<IsBoolean<never, 1, 2>, 2>(true)
testType.equal<IsBoolean<void, 1, 2>, 2>(true)
testType.equal<IsBoolean<any, IsBoolean.$Branch>, $Else>(true)
testType.equal<IsBoolean<unknown, IsBoolean.$Branch>, $Else>(true)
testType.equal<IsBoolean<never, IsBoolean.$Branch>, $Else>(true)
testType.equal<IsBoolean<void, IsBoolean.$Branch>, $Else>(true)
})
16 changes: 8 additions & 8 deletions type-plus/ts/boolean/is_boolean.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { IsAnyOrNever } from '../mix_types/is_any_or_never.js'
import type { $Else, $SelectionBranch, $Then } from '../type_plus/branch/selection.js'
import type { SelectWithDistribute } from '../type_plus/branch/select_with_distribute.js'

/**
* Is the type `T` `boolean`, including `true` and `false`.
Expand All @@ -14,9 +13,10 @@ import type { $Else, $SelectionBranch, $Then } from '../type_plus/branch/selecti
* ```
*/

export type IsBoolean<T, Then = true, Else = false> = IsAnyOrNever<
T,
$SelectionBranch> extends infer R
? R extends $Then ? Else
: R extends $Else ? [T] extends [boolean] ? Then : Else
: never : never
export type IsBoolean<T, $O extends IsBoolean.$Options = {}> = SelectWithDistribute<T, boolean, $O>

export namespace IsBoolean {
export type $Options = SelectWithDistribute.$Options
export type $Default = SelectWithDistribute.$Default
export type $Branch = SelectWithDistribute.$Branch
}
105 changes: 63 additions & 42 deletions type-plus/ts/boolean/is_false.spec.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,74 @@
import { it } from '@jest/globals'
import { testType, type IsFalse } from '../index.js'
import { testType, type IsFalse, type $Then, type $Else } from '../index.js'

it('returns true if T is false', () => {
testType.true<IsFalse<false>>(true)
testType.equal<IsFalse<false>, true>(true)
})

it('returns false if T is boolean or true', () => {
testType.false<IsFalse<boolean>>(true)
testType.false<IsFalse<true>>(true)
it('returns boolean if T is boolean because it is distributive by default', () => {
testType.equal<IsFalse<boolean>, boolean>(true)
testType.equal<IsFalse<boolean, { distributive: false }>, false>(true)
})

it('returns false if T is true', () => {
testType.equal<IsFalse<true>, false>(true)
})

it('returns false for special types', () => {
testType.false<IsFalse<void>>(true)
testType.false<IsFalse<unknown>>(true)
testType.false<IsFalse<any>>(true)
testType.false<IsFalse<never>>(true)
testType.equal<IsFalse<void>, false>(true)
testType.equal<IsFalse<unknown>, false>(true)
testType.equal<IsFalse<any>, false>(true)
testType.equal<IsFalse<never>, false>(true)
})

it('returns false for other types', () => {
testType.false<IsFalse<undefined>>(true)
testType.false<IsFalse<null>>(true)
testType.false<IsFalse<number>>(true)
testType.false<IsFalse<1>>(true)
testType.false<IsFalse<string>>(true)
testType.false<IsFalse<''>>(true)
testType.false<IsFalse<symbol>>(true)
testType.false<IsFalse<bigint>>(true)
testType.false<IsFalse<1n>>(true)
testType.false<IsFalse<{}>>(true)
testType.false<IsFalse<{ a: 1 }>>(true)
testType.false<IsFalse<string[]>>(true)
testType.false<IsFalse<[]>>(true)
testType.false<IsFalse<Function>>(true)
testType.false<IsFalse<() => void>>(true)
})

it('returns false for union type', () => {
testType.false<IsFalse<false | 1>>(true)
testType.false<IsFalse<false | boolean>>(true)
})

it('returns false for intersection type', () => {
testType.false<IsFalse<false & { a: 1 }>>(true)
})

it('can override Then/Else', () => {
testType.equal<IsFalse<false, 1, 2>, 1>(true)

testType.equal<IsFalse<any, 1, 2>, 2>(true)
testType.equal<IsFalse<unknown, 1, 2>, 2>(true)
testType.equal<IsFalse<never, 1, 2>, 2>(true)
testType.equal<IsFalse<void, 1, 2>, 2>(true)
testType.equal<IsFalse<undefined>, false>(true)
testType.equal<IsFalse<null>, false>(true)
testType.equal<IsFalse<number>, false>(true)
testType.equal<IsFalse<1>, false>(true)
testType.equal<IsFalse<string>, false>(true)
testType.equal<IsFalse<''>, false>(true)
testType.equal<IsFalse<symbol>, false>(true)
testType.equal<IsFalse<bigint>, false>(true)
testType.equal<IsFalse<1n>, false>(true)
testType.equal<IsFalse<{}>, false>(true)
testType.equal<IsFalse<{ a: 1 }>, false>(true)
testType.equal<IsFalse<string[]>, false>(true)
testType.equal<IsFalse<[]>, false>(true)
testType.equal<IsFalse<Function>, false>(true)
testType.equal<IsFalse<() => void>, false>(true)
})

it('distributes over union type', () => {
testType.equal<IsFalse<false | 1>, boolean>(true)
})

it('can disable union distribution', () => {
testType.equal<IsFalse<false | 1, { distributive: false }>, false>(true)
})

it('returns true for intersection type', () => {
testType.equal<IsFalse<false & { a: 1 }>, true>(true)
})

it('works as filter', () => {
testType.equal<IsFalse<false, { selection: 'filter' }>, false>(true)
testType.equal<IsFalse<true, { selection: 'filter' }>, never>(true)
testType.equal<IsFalse<boolean, { selection: 'filter' }>, false>(true)
testType.equal<IsFalse<boolean, { selection: 'filter', distributive: false }>, never>(true)

testType.equal<IsFalse<never, { selection: 'filter' }>, never>(true)
testType.equal<IsFalse<unknown, { selection: 'filter' }>, never>(true)
testType.equal<IsFalse<string | false, { selection: 'filter' }>, false>(true)

testType.equal<IsFalse<string | true, { selection: 'filter' }>, never>(true)
})

it('works with unique branches', () => {
testType.equal<IsFalse<false, IsFalse.$Branch>, $Then>(true)

testType.equal<IsFalse<any, IsFalse.$Branch>, $Else>(true)
testType.equal<IsFalse<unknown, IsFalse.$Branch>, $Else>(true)
testType.equal<IsFalse<never, IsFalse.$Branch>, $Else>(true)
testType.equal<IsFalse<void, IsFalse.$Branch>, $Else>(true)
})
17 changes: 8 additions & 9 deletions type-plus/ts/boolean/is_false.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { IsAnyOrNever } from '../mix_types/is_any_or_never.js'
import type { $Else, $SelectionBranch, $Then } from '../type_plus/branch/selection.js'
import type { SelectWithDistribute } from '../type_plus/branch/select_with_distribute.js'

/**
* Is the type `T` exactly `false`.
Expand All @@ -12,10 +11,10 @@ import type { $Else, $SelectionBranch, $Then } from '../type_plus/branch/selecti
* ```
*/

export type IsFalse<T, Then = true, Else = false> = IsAnyOrNever<
T,
$SelectionBranch
> extends infer R
? R extends $Then ? Else
: R extends $Else ? [T, false] extends [false, T] ? Then : Else
: never : never
export type IsFalse<T, $O extends IsFalse.$Options = {}> = SelectWithDistribute<T, false, $O>

export namespace IsFalse {
export type $Options = SelectWithDistribute.$Options
export type $Default = SelectWithDistribute.$Default
export type $Branch = SelectWithDistribute.$Branch
}
38 changes: 26 additions & 12 deletions type-plus/ts/boolean/is_not_boolean.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { it } from '@jest/globals'
import { testType, type IsNotBoolean } from '../index.js'
import { testType, type IsNotBoolean, type $Then, type $Else } from '../index.js'

it('returns false if T is boolean', () => {
testType.false<IsNotBoolean<boolean>>(true)
Expand Down Expand Up @@ -33,21 +33,35 @@ it('returns true for all other types', () => {
testType.true<IsNotBoolean<() => void>>(true)
})

it('returns true for union type', () => {
testType.true<IsNotBoolean<boolean | 1>>(true)
it('distributes over union type', () => {
testType.equal<IsNotBoolean<boolean | 1>, boolean>(true)
})

it('returns false for intersection type', () => {
it('can disable union distribution', () => {
testType.true<IsNotBoolean<boolean | 1, { distributive: false }>>(true)
})

it('returns true for intersection type', () => {
testType.false<IsNotBoolean<boolean & { a: 1 }>>(true)
})

it('can override Then/Else', () => {
testType.equal<IsNotBoolean<boolean, 1, 2>, 2>(true)
testType.equal<IsNotBoolean<true, 1, 2>, 2>(true)
testType.equal<IsNotBoolean<false, 1, 2>, 2>(true)
it('works as filter', () => {
testType.equal<IsNotBoolean<boolean, { selection: 'filter' }>, never>(true)
testType.equal<IsNotBoolean<true, { selection: 'filter' }>, never>(true)

testType.equal<IsNotBoolean<never, { selection: 'filter' }>, never>(true)
testType.equal<IsNotBoolean<unknown, { selection: 'filter' }>, unknown>(true)
testType.equal<IsNotBoolean<string | boolean, { selection: 'filter' }>, string>(true)
testType.equal<IsNotBoolean<string | boolean, { selection: 'filter', distributive: false }>, string | boolean>(true)

testType.equal<IsNotBoolean<string | true, { selection: 'filter' }>, string>(true)
})

it('works with unique branches', () => {
testType.equal<IsNotBoolean<boolean, IsNotBoolean.$Branch>, $Else>(true)

testType.equal<IsNotBoolean<any, 1, 2>, 1>(true)
testType.equal<IsNotBoolean<unknown, 1, 2>, 1>(true)
testType.equal<IsNotBoolean<never, 1, 2>, 1>(true)
testType.equal<IsNotBoolean<void, 1, 2>, 1>(true)
testType.equal<IsNotBoolean<any, IsNotBoolean.$Branch>, $Then>(true)
testType.equal<IsNotBoolean<unknown, IsNotBoolean.$Branch>, $Then>(true)
testType.equal<IsNotBoolean<never, IsNotBoolean.$Branch>, $Then>(true)
testType.equal<IsNotBoolean<void, IsNotBoolean.$Branch>, $Then>(true)
})
15 changes: 7 additions & 8 deletions type-plus/ts/boolean/is_not_boolean.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { IsAnyOrNever } from '../mix_types/is_any_or_never.js'
import type { $Else, $SelectionBranch, $Then } from '../type_plus/branch/selection.js'
import type { SelectInvertWithDistribute } from '../type_plus/branch/select_invert_with_distribute.js'

/**
* Is the type `T` not `boolean`, including `true` and `false`.
Expand All @@ -13,10 +12,10 @@ import type { $Else, $SelectionBranch, $Then } from '../type_plus/branch/selecti
* type R = IsNotBoolean<unknown> // true
* ```
*/
export type IsNotBoolean<T, $O extends IsNotBoolean.$Options = {}> = SelectInvertWithDistribute<T, boolean, $O>

export type IsNotBoolean<T, Then = true, Else = false> = IsAnyOrNever<
T,
$SelectionBranch> extends infer R
? R extends $Then ? Then
: R extends $Else ? [T] extends [boolean] ? Else : Then
: never : never
export namespace IsNotBoolean {
export type $Options = SelectInvertWithDistribute.$Options
export type $Default = SelectInvertWithDistribute.$Default
export type $Branch = SelectInvertWithDistribute.$Branch
}
Loading

0 comments on commit 53440e5

Please sign in to comment.