From 3632179e9009d4075ca94c19a590ccb12489e243 Mon Sep 17 00:00:00 2001 From: Lexus Drumgold Date: Mon, 15 May 2023 16:26:06 -0400 Subject: [PATCH] feat(types): `Float`, `Integer` Signed-off-by: Lexus Drumgold --- src/types/__tests__/float.spec-d.ts | 17 +++++++++++++++++ src/types/__tests__/integer.spec-d.ts | 17 +++++++++++++++++ src/types/__tests__/opaque.spec-d.ts | 11 ++++------- src/types/float.ts | 15 +++++++++++++++ src/types/index.ts | 2 ++ src/types/integer.ts | 16 ++++++++++++++++ src/types/opaque.ts | 12 ++++++++---- 7 files changed, 79 insertions(+), 11 deletions(-) create mode 100644 src/types/__tests__/float.spec-d.ts create mode 100644 src/types/__tests__/integer.spec-d.ts create mode 100644 src/types/float.ts create mode 100644 src/types/integer.ts diff --git a/src/types/__tests__/float.spec-d.ts b/src/types/__tests__/float.spec-d.ts new file mode 100644 index 00000000..959c2364 --- /dev/null +++ b/src/types/__tests__/float.spec-d.ts @@ -0,0 +1,17 @@ +/** + * @file Type Tests - Float + * @module tutils/types/tests/unit-d/Float + */ + +import type TestSubject from '../float' +import type { tag } from '../opaque' + +describe('unit-d:types/Float', () => { + it('should extend number', () => { + expectTypeOf().toMatchTypeOf() + }) + + it('should match [readonly [tag]: "float"]', () => { + expectTypeOf().toMatchTypeOf<{ readonly [tag]: 'float' }>() + }) +}) diff --git a/src/types/__tests__/integer.spec-d.ts b/src/types/__tests__/integer.spec-d.ts new file mode 100644 index 00000000..b8688efe --- /dev/null +++ b/src/types/__tests__/integer.spec-d.ts @@ -0,0 +1,17 @@ +/** + * @file Type Tests - Integer + * @module tutils/types/tests/unit-d/Integer + */ + +import type TestSubject from '../integer' +import type { tag } from '../opaque' + +describe('unit-d:types/Integer', () => { + it('should extend number', () => { + expectTypeOf().toMatchTypeOf() + }) + + it('should match [readonly [tag]: "integer"]', () => { + expectTypeOf().toMatchTypeOf<{ readonly [tag]: 'integer' }>() + }) +}) diff --git a/src/types/__tests__/opaque.spec-d.ts b/src/types/__tests__/opaque.spec-d.ts index afc9b8cd..aab8b7d3 100644 --- a/src/types/__tests__/opaque.spec-d.ts +++ b/src/types/__tests__/opaque.spec-d.ts @@ -4,20 +4,17 @@ */ import type TestSubject from '../opaque' +import type { tag } from '../opaque' describe('unit-d:types/Opaque', () => { type B = number type T = 'account-number' - it('should be assignable to type of B', () => { + it('should extend B', () => { expectTypeOf>().toMatchTypeOf() }) - it('should not match opaque type with same base and different token', () => { - // Arrange - type T2 = 'account-balance' - - // Expect - expectTypeOf>().not.toMatchTypeOf>() + it('should match [readonly [tag]: T]', () => { + expectTypeOf>().toMatchTypeOf<{ readonly [tag]: T }>() }) }) diff --git a/src/types/float.ts b/src/types/float.ts new file mode 100644 index 00000000..f8d0a1cb --- /dev/null +++ b/src/types/float.ts @@ -0,0 +1,15 @@ +/** + * @file Type Definitions - Float + * @module tutils/types/Float + */ + +import type Opaque from './opaque' + +/** + * A floating point number. + * + * @see https://computersciencewiki.org/index.php/float + */ +type Float = Opaque + +export type { Float as default } diff --git a/src/types/index.ts b/src/types/index.ts index 0f394c3c..bbcc6f60 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -19,6 +19,7 @@ export type { default as EnsureString } from './ensure-string' export type { default as ExactOptionalPropertyTypes } from './exact-optional-property-types' export type { default as Fallback } from './fallback' export type { default as FIXME } from './fixme' +export type { default as Float } from './float' export type { default as Fn } from './fn' export type { default as Get } from './get' export type { default as IfAny } from './if-any' @@ -40,6 +41,7 @@ export type { default as IfUndefined } from './if-undefined' export type { default as IfUnknown } from './if-unknown' export type { default as IndexSignature } from './index-signature' export type { default as Indices } from './indices' +export type { default as Integer } from './integer' export type { default as IsAny } from './is-any' export type { default as IsArray } from './is-array' export type { default as IsBigInt } from './is-big-int' diff --git a/src/types/integer.ts b/src/types/integer.ts new file mode 100644 index 00000000..79765e74 --- /dev/null +++ b/src/types/integer.ts @@ -0,0 +1,16 @@ +/** + * @file Type Definitions - Integer + * @module tutils/types/Integer + */ + +import type Opaque from './opaque' + +/** + * A number that can be negative, positive, or zero, but not a fraction (i.e. + * cannot have a decimal point). + * + * @see https://computersciencewiki.org/index.php/int + */ +type Integer = Opaque + +export type { Integer as default } diff --git a/src/types/opaque.ts b/src/types/opaque.ts index 8c394437..f7c50ede 100644 --- a/src/types/opaque.ts +++ b/src/types/opaque.ts @@ -4,9 +4,9 @@ */ /** - * Token symbol for {@linkcode Opaque}. + * {@linkcode Opaque} type token key. */ -declare const token: unique symbol +export declare const tag: unique symbol /** * Creates an [opaque type][1]. @@ -17,11 +17,15 @@ declare const token: unique symbol * The type token parameter, `T`, allows TypeScript to differentiate between * opaque types with the same base type. * - * [1]: https://codemix.com/opaque-types-in-javascript/ + * [1]: https://codemix.com/opaque-types-in-javascript + * + * @see https://github.com/Microsoft/TypeScript/issues/202 + * @see https://github.com/Microsoft/TypeScript/issues/15408 + * @see https://github.com/Microsoft/TypeScript/issues/15807 * * @template B - Base type * @template T - Type token */ -type Opaque = B & { readonly [token]: T } +type Opaque = B & { readonly [tag]: T } export type { Opaque as default }