From 95f442bbdf010ed4e43dc2d6879d82238fbe1944 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Tue, 8 Oct 2024 21:01:24 -0500 Subject: [PATCH] Add `.toBeBigInt()` (#123) ## **This PR**: - [X] Adds the **`.toBeBigInt()`** matcher: This new matcher works similarly to **`.toBeNumber()`**, but is designed specifically for testing values of type **`bigint`**. --- README.md | 10 ++++ src/index.ts | 46 +++++++++++++----- src/messages.ts | 66 +++++++++++++++++++++----- test/__snapshots__/errors.test.ts.snap | 5 ++ test/usage.test.ts | 10 ++++ 5 files changed, 113 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index b148ed7..9596fa3 100644 --- a/README.md +++ b/README.md @@ -166,6 +166,7 @@ expectTypeOf(true).toBeBoolean() expectTypeOf(() => {}).returns.toBeVoid() expectTypeOf(Promise.resolve(123)).resolves.toBeNumber() expectTypeOf(Symbol(1)).toBeSymbol() +expectTypeOf(1n).toBeBigInt() ``` `.toBe...` methods allow for types that extend the expected type: @@ -182,6 +183,9 @@ expectTypeOf<'foo'>().toBeString() expectTypeOf().toBeBoolean() expectTypeOf().toBeBoolean() + +expectTypeOf().toBeBigInt() +expectTypeOf<0n>().toBeBigInt() ``` `.toBe...` methods protect against `any`: @@ -220,6 +224,7 @@ expectTypeOf(1).not.toBeNever() expectTypeOf(1).not.toBeNull() expectTypeOf(1).not.toBeUndefined() expectTypeOf(1).not.toBeNullable() +expectTypeOf(1).not.toBeBigInt() ``` Detect assignability of unioned types: @@ -440,7 +445,12 @@ const assertNumber = (v: any): asserts v is number => { expectTypeOf(assertNumber).asserts.toBeNumber() const isString = (v: any): v is string => typeof v === 'string' + expectTypeOf(isString).guards.toBeString() + +const isBigInt = (value: any): value is bigint => typeof value === 'bigint' + +expectTypeOf(isBigInt).guards.toBeBigInt() ``` Assert on constructor parameters: diff --git a/src/index.ts b/src/index.ts index e787c30..0070d52 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,21 +1,22 @@ import type {StrictEqualUsingBranding} from './branding' import type { - MismatchInfo, - Scolder, ExpectAny, - ExpectUnknown, - ExpectNever, - ExpectFunction, - ExpectObject, ExpectArray, + ExpectBigInt, + ExpectBoolean, + ExpectFunction, + ExpectNever, + ExpectNull, + ExpectNullable, ExpectNumber, + ExpectObject, ExpectString, - ExpectBoolean, - ExpectVoid, ExpectSymbol, - ExpectNull, ExpectUndefined, - ExpectNullable, + ExpectUnknown, + ExpectVoid, + MismatchInfo, + Scolder, } from './messages' import type { ConstructorOverloadParameters, @@ -23,12 +24,12 @@ import type { OverloadReturnTypes, OverloadsNarrowedByParameters, } from './overloads' -import type {StrictEqualUsingTSInternalIdenticalToOperator, AValue, MismatchArgs, Extends} from './utils' +import type {AValue, Extends, MismatchArgs, StrictEqualUsingTSInternalIdenticalToOperator} from './utils' export * from './branding' // backcompat, consider removing in next major version -export * from './utils' // backcompat, consider removing in next major version export * from './messages' // backcompat, consider removing in next major version export * from './overloads' +export * from './utils' // backcompat, consider removing in next major version /** * Represents the positive assertion methods available for type checking in the @@ -498,6 +499,26 @@ export interface BaseExpectTypeOf { */ toBeNullable: Scolder, Options> + /** + * Checks whether the type of the value is **`bigint`**. + * + * @example + * #### Distinguish between **`number`** and **`bigint`** + * + * ```ts + * import { expectTypeOf } from 'expect-type' + * + * const aVeryBigInteger = 10n ** 100n + * + * expectTypeOf(aVeryBigInteger).not.toBeNumber() + * + * expectTypeOf(aVeryBigInteger).toBeBigInt() + * ``` + * + * @since 1.1.0 + */ + toBeBigInt: Scolder, Options> + /** * Checks whether a function is callable with the given parameters. * @@ -908,6 +929,7 @@ export const expectTypeOf: _ExpectTypeOf = ( toBeNull: fn, toBeUndefined: fn, toBeNullable: fn, + toBeBigInt: fn, toMatchTypeOf: fn, toEqualTypeOf: fn, toBeConstructibleWith: fn, diff --git a/src/messages.ts b/src/messages.ts index d3ac13a..916daa9 100644 --- a/src/messages.ts +++ b/src/messages.ts @@ -1,5 +1,5 @@ import type {StrictEqualUsingBranding} from './branding' -import type {And, Extends, Not, IsAny, UsefulKeys, ExtendsExcludingAnyOrNever, IsUnknown, IsNever} from './utils' +import type {And, Extends, ExtendsExcludingAnyOrNever, IsAny, IsNever, IsUnknown, Not, UsefulKeys} from './utils' /** * Determines the printable type representation for a given type. @@ -65,61 +65,91 @@ type Inverted = {[inverted]: T} * @internal */ const expectNull = Symbol('expectNull') -export type ExpectNull = {[expectNull]: T; result: ExtendsExcludingAnyOrNever} +export type ExpectNull = { + [expectNull]: T + result: ExtendsExcludingAnyOrNever +} /** * @internal */ const expectUndefined = Symbol('expectUndefined') -export type ExpectUndefined = {[expectUndefined]: T; result: ExtendsExcludingAnyOrNever} +export type ExpectUndefined = { + [expectUndefined]: T + result: ExtendsExcludingAnyOrNever +} /** * @internal */ const expectNumber = Symbol('expectNumber') -export type ExpectNumber = {[expectNumber]: T; result: ExtendsExcludingAnyOrNever} +export type ExpectNumber = { + [expectNumber]: T + result: ExtendsExcludingAnyOrNever +} /** * @internal */ const expectString = Symbol('expectString') -export type ExpectString = {[expectString]: T; result: ExtendsExcludingAnyOrNever} +export type ExpectString = { + [expectString]: T + result: ExtendsExcludingAnyOrNever +} /** * @internal */ const expectBoolean = Symbol('expectBoolean') -export type ExpectBoolean = {[expectBoolean]: T; result: ExtendsExcludingAnyOrNever} +export type ExpectBoolean = { + [expectBoolean]: T + result: ExtendsExcludingAnyOrNever +} /** * @internal */ const expectVoid = Symbol('expectVoid') -export type ExpectVoid = {[expectVoid]: T; result: ExtendsExcludingAnyOrNever} +export type ExpectVoid = { + [expectVoid]: T + result: ExtendsExcludingAnyOrNever +} /** * @internal */ const expectFunction = Symbol('expectFunction') -export type ExpectFunction = {[expectFunction]: T; result: ExtendsExcludingAnyOrNever any>} +export type ExpectFunction = { + [expectFunction]: T + result: ExtendsExcludingAnyOrNever any> +} /** * @internal */ const expectObject = Symbol('expectObject') -export type ExpectObject = {[expectObject]: T; result: ExtendsExcludingAnyOrNever} +export type ExpectObject = { + [expectObject]: T + result: ExtendsExcludingAnyOrNever +} /** * @internal */ const expectArray = Symbol('expectArray') -export type ExpectArray = {[expectArray]: T; result: ExtendsExcludingAnyOrNever} +export type ExpectArray = { + [expectArray]: T + result: ExtendsExcludingAnyOrNever +} /** * @internal */ const expectSymbol = Symbol('expectSymbol') -export type ExpectSymbol = {[expectSymbol]: T; result: ExtendsExcludingAnyOrNever} +export type ExpectSymbol = { + [expectSymbol]: T + result: ExtendsExcludingAnyOrNever +} /** * @internal @@ -143,7 +173,19 @@ export type ExpectNever = {[expectNever]: T; result: IsNever} * @internal */ const expectNullable = Symbol('expectNullable') -export type ExpectNullable = {[expectNullable]: T; result: Not>>} +export type ExpectNullable = { + [expectNullable]: T + result: Not>> +} + +/** + * @internal + */ +const expectBigInt = Symbol('expectBigInt') +export type ExpectBigInt = { + [expectBigInt]: T + result: ExtendsExcludingAnyOrNever +} /** * Checks if the result of an expecter matches the specified options, and diff --git a/test/__snapshots__/errors.test.ts.snap b/test/__snapshots__/errors.test.ts.snap index 4a4a494..05ac2ff 100644 --- a/test/__snapshots__/errors.test.ts.snap +++ b/test/__snapshots__/errors.test.ts.snap @@ -100,6 +100,11 @@ test/usage.test.ts:999:999 - error TS2349: This expression is not callable. 999 expectTypeOf(1).toBeNullable() ~~~~~~~~~~~~ +test/usage.test.ts:999:999 - error TS2349: This expression is not callable. + Type 'ExpectBigInt' has no call signatures. + +999 expectTypeOf(1).toBeBigInt() + ~~~~~~~~~~ test/usage.test.ts:999:999 - error TS2344: Type 'number' does not satisfy the constraint '"Expected: number, Actual: string"'. 999 expectTypeOf().toMatchTypeOf() diff --git a/test/usage.test.ts b/test/usage.test.ts index 6f08643..f39b95f 100644 --- a/test/usage.test.ts +++ b/test/usage.test.ts @@ -82,6 +82,7 @@ test('You can test for basic JavaScript types', () => { expectTypeOf(() => {}).returns.toBeVoid() expectTypeOf(Promise.resolve(123)).resolves.toBeNumber() expectTypeOf(Symbol(1)).toBeSymbol() + expectTypeOf(1n).toBeBigInt() }) test('`.toBe...` methods allow for types that extend the expected type', () => { @@ -96,6 +97,9 @@ test('`.toBe...` methods allow for types that extend the expected type', () => { expectTypeOf().toBeBoolean() expectTypeOf().toBeBoolean() + + expectTypeOf().toBeBigInt() + expectTypeOf<0n>().toBeBigInt() }) test('`.toBe...` methods protect against `any`', () => { @@ -128,6 +132,7 @@ test('More `.not` examples', () => { expectTypeOf(1).not.toBeNull() expectTypeOf(1).not.toBeUndefined() expectTypeOf(1).not.toBeNullable() + expectTypeOf(1).not.toBeBigInt() }) test('Detect assignability of unioned types', () => { @@ -315,7 +320,12 @@ test('You can also check type guards & type assertions', () => { expectTypeOf(assertNumber).asserts.toBeNumber() const isString = (v: any): v is string => typeof v === 'string' + expectTypeOf(isString).guards.toBeString() + + const isBigInt = (value: any): value is bigint => typeof value === 'bigint' + + expectTypeOf(isBigInt).guards.toBeBigInt() }) test('Assert on constructor parameters', () => {