Skip to content

Commit

Permalink
feat(types): IsUniqueSymbol, IfUniqueSymbol
Browse files Browse the repository at this point in the history
Signed-off-by: Lexus Drumgold <[email protected]>
  • Loading branch information
unicornware committed Aug 3, 2023
1 parent 0482471 commit 9405a9e
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 0 deletions.
40 changes: 40 additions & 0 deletions src/types/__tests__/if-symbol-unique.spec-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* @file Type Tests - IfUniqueSymbol
* @module tutils/types/tests/unit-d/IfUniqueSymbol
*/

import type { tag as empty } from '../empty-object'
import type TestSubject from '../if-symbol-unique'
import type Nilable from '../nilable'
import type { tag as opaque } from '../opaque'

describe('unit-d:types/IfUniqueSymbol', () => {
type F = 0
type T = 1

it('should equal F if IsUniqueSymbol<U> extends false', () => {
expectTypeOf<TestSubject<unknown, T, F>>().toEqualTypeOf<F>()
})

it('should equal F if U is any', () => {
expectTypeOf<TestSubject<any, T, F>>().toEqualTypeOf<F>()
})

it('should equal F if U is never', () => {
expectTypeOf<TestSubject<never, T, F>>().toEqualTypeOf<F>()
})

it('should equal T if IsUniqueSymbol<U> extends true', () => {
expectTypeOf<TestSubject<typeof empty, T, F>>().toEqualTypeOf<T>()
})

describe('unions', () => {
it('should distribute over unions', () => {
// Arrange
type U = Nilable<typeof opaque>

// Expect
expectTypeOf<TestSubject<U, T, F>>().toEqualTypeOf<F | T>()
})
})
})
42 changes: 42 additions & 0 deletions src/types/__tests__/is-symbol-unique.spec-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* @file Type Tests - IsUniqueSymbol
* @module tutils/types/tests/unit-d/IsUniqueSymbol
*/

import type EmptyObject from '../empty-object'
import type Integer from '../integer'
import type TestSubject from '../is-symbol-unique'
import type { tag as opaque } from '../opaque'

describe('unit-d:types/IsUniqueSymbol', () => {
it('should equal false if T does not extend symbol', () => {
expectTypeOf<TestSubject<unknown>>().toEqualTypeOf<false>()
})

it('should equal false if T extends object', () => {
expectTypeOf<TestSubject<symbol & { id: string }>>().toEqualTypeOf<false>()
})

it('should equal false if T is any', () => {
expectTypeOf<TestSubject<any>>().toEqualTypeOf<false>()
})

it('should equal false if T is never', () => {
expectTypeOf<TestSubject<never>>().toEqualTypeOf<false>()
})

it('should equal false if symbol extends T', () => {
expectTypeOf<TestSubject<symbol>>().toEqualTypeOf<false>()
})

it('should equal true if T is unique symbol', () => {
expectTypeOf<TestSubject<keyof EmptyObject>>().toEqualTypeOf<true>()
expectTypeOf<TestSubject<typeof opaque>>().toEqualTypeOf<true>()
})

describe('unions', () => {
it('should distribute over unions', () => {
expectTypeOf<TestSubject<keyof Integer>>().toEqualTypeOf<boolean>()
})
})
})
43 changes: 43 additions & 0 deletions src/types/if-symbol-unique.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* @file Type Definitions - IfUniqueSymbol
* @module tutils/types/IfUniqueSymbol
*/

import type IfNever from './if-never'
import type IsUniqueSymbol from './is-symbol-unique'

/**
* Returns a type that indicates if `U` is a type of `unique symbol`.
*
* @see {@linkcode IsUniqueSymbol}
*
* @example
* type X = IfUniqueSymbol<keyof EmptyObject, 1, 0>
* // 1
* @example
* type X = IfUniqueSymbol<keyof Integer, 1, 0>
* // 0 | 1
* @example
* type X = IfUniqueSymbol<symbol, 1, 0>
* // 0
* @example
* type X = IfUniqueSymbol<any, 1, 0>
* // 0
* @example
* type X = IfUniqueSymbol<never, 1, 0>
* // 0
* @example
* type X = IfUniqueSymbol<unknown, 1, 0>
* // 0
*
* @template U - Type to evaluate
* @template T - Type if `U` is `unique symbol`
* @template F - Type if `U` is not a `unique symbol`
*/
type IfUniqueSymbol<U, T, F> = IfNever<
U,
F,
U extends unknown ? (IsUniqueSymbol<U> extends true ? T : F) : F
>

export type { IfUniqueSymbol as default }
2 changes: 2 additions & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export type { default as IfObjectPlain } from './if-object-plain'
export type { default as IfPrimitive } from './if-primitive'
export type { default as IfString } from './if-string'
export type { default as IfSymbol } from './if-symbol'
export type { default as IfUniqueSymbol } from './if-symbol-unique'
export type { default as IfTrue } from './if-true'
export type { default as IfTuple } from './if-tuple'
export type { default as IfUndefined } from './if-undefined'
Expand Down Expand Up @@ -106,6 +107,7 @@ export type { default as IsObjectPlain } from './is-object-plain'
export type { default as IsPrimitive } from './is-primitive'
export type { default as IsString } from './is-string'
export type { default as IsSymbol } from './is-symbol'
export type { default as IsUniqueSymbol } from './is-symbol-unique'
export type { default as IsTrue } from './is-true'
export type { default as IsTuple } from './is-tuple'
export type { default as IsUndefined } from './is-undefined'
Expand Down
44 changes: 44 additions & 0 deletions src/types/is-symbol-unique.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* @file Type Definitions - IsUniqueSymbol
* @module tutils/types/IsUniqueSymbol
*/

import type IfAnyOrNever from './if-any-or-never'

/**
* Returns a boolean indicating if `T` is a type of `unique symbol`.
*
* @example
* type X = IsSymbol<keyof EmptyObject>
* // true
* @example
* type X = IsSymbol<keyof Integer>
* // boolean
* @example
* type X = IsSymbol<symbol>
* // false
* @example
* type X = IsSymbol<any>
* // false
* @example
* type X = IsSymbol<never>
* // false
* @example
* type X = IsSymbol<unknown>
* // false
*
* @template T - Type to evaluate
*/
type IsUniqueSymbol<T> = IfAnyOrNever<
T,
false,
T extends symbol
? symbol extends T
? false
: T extends object
? false
: true
: false
>

export type { IsUniqueSymbol as default }

0 comments on commit 9405a9e

Please sign in to comment.