Skip to content

Commit

Permalink
Add .toBeBigInt() (#123)
Browse files Browse the repository at this point in the history
## **This PR**:

- [X] Adds the **`.toBeBigInt()`** matcher: This new matcher works
similarly to **`.toBeNumber()`**, but is designed specifically for
testing values of type **`bigint`**.
  • Loading branch information
aryaemami59 authored Oct 9, 2024
1 parent 5862740 commit 95f442b
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 24 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -182,6 +183,9 @@ expectTypeOf<'foo'>().toBeString()

expectTypeOf<boolean>().toBeBoolean()
expectTypeOf<true>().toBeBoolean()

expectTypeOf<bigint>().toBeBigInt()
expectTypeOf<0n>().toBeBigInt()
```

`.toBe...` methods protect against `any`:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
46 changes: 34 additions & 12 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,35 @@
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,
OverloadParameters,
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
Expand Down Expand Up @@ -498,6 +499,26 @@ export interface BaseExpectTypeOf<Actual, Options extends {positive: boolean}> {
*/
toBeNullable: Scolder<ExpectNullable<Actual>, Options>

/**
* Checks whether the type of the value is **`bigint`**.
*
* @example
* <caption>#### Distinguish between **`number`** and **`bigint`**</caption>
*
* ```ts
* import { expectTypeOf } from 'expect-type'
*
* const aVeryBigInteger = 10n ** 100n
*
* expectTypeOf(aVeryBigInteger).not.toBeNumber()
*
* expectTypeOf(aVeryBigInteger).toBeBigInt()
* ```
*
* @since 1.1.0
*/
toBeBigInt: Scolder<ExpectBigInt<Actual>, Options>

/**
* Checks whether a function is callable with the given parameters.
*
Expand Down Expand Up @@ -908,6 +929,7 @@ export const expectTypeOf: _ExpectTypeOf = <Actual>(
toBeNull: fn,
toBeUndefined: fn,
toBeNullable: fn,
toBeBigInt: fn,
toMatchTypeOf: fn,
toEqualTypeOf: fn,
toBeConstructibleWith: fn,
Expand Down
66 changes: 54 additions & 12 deletions src/messages.ts
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -65,61 +65,91 @@ type Inverted<T> = {[inverted]: T}
* @internal
*/
const expectNull = Symbol('expectNull')
export type ExpectNull<T> = {[expectNull]: T; result: ExtendsExcludingAnyOrNever<T, null>}
export type ExpectNull<T> = {
[expectNull]: T
result: ExtendsExcludingAnyOrNever<T, null>
}

/**
* @internal
*/
const expectUndefined = Symbol('expectUndefined')
export type ExpectUndefined<T> = {[expectUndefined]: T; result: ExtendsExcludingAnyOrNever<T, undefined>}
export type ExpectUndefined<T> = {
[expectUndefined]: T
result: ExtendsExcludingAnyOrNever<T, undefined>
}

/**
* @internal
*/
const expectNumber = Symbol('expectNumber')
export type ExpectNumber<T> = {[expectNumber]: T; result: ExtendsExcludingAnyOrNever<T, number>}
export type ExpectNumber<T> = {
[expectNumber]: T
result: ExtendsExcludingAnyOrNever<T, number>
}

/**
* @internal
*/
const expectString = Symbol('expectString')
export type ExpectString<T> = {[expectString]: T; result: ExtendsExcludingAnyOrNever<T, string>}
export type ExpectString<T> = {
[expectString]: T
result: ExtendsExcludingAnyOrNever<T, string>
}

/**
* @internal
*/
const expectBoolean = Symbol('expectBoolean')
export type ExpectBoolean<T> = {[expectBoolean]: T; result: ExtendsExcludingAnyOrNever<T, boolean>}
export type ExpectBoolean<T> = {
[expectBoolean]: T
result: ExtendsExcludingAnyOrNever<T, boolean>
}

/**
* @internal
*/
const expectVoid = Symbol('expectVoid')
export type ExpectVoid<T> = {[expectVoid]: T; result: ExtendsExcludingAnyOrNever<T, void>}
export type ExpectVoid<T> = {
[expectVoid]: T
result: ExtendsExcludingAnyOrNever<T, void>
}

/**
* @internal
*/
const expectFunction = Symbol('expectFunction')
export type ExpectFunction<T> = {[expectFunction]: T; result: ExtendsExcludingAnyOrNever<T, (...args: any[]) => any>}
export type ExpectFunction<T> = {
[expectFunction]: T
result: ExtendsExcludingAnyOrNever<T, (...args: any[]) => any>
}

/**
* @internal
*/
const expectObject = Symbol('expectObject')
export type ExpectObject<T> = {[expectObject]: T; result: ExtendsExcludingAnyOrNever<T, object>}
export type ExpectObject<T> = {
[expectObject]: T
result: ExtendsExcludingAnyOrNever<T, object>
}

/**
* @internal
*/
const expectArray = Symbol('expectArray')
export type ExpectArray<T> = {[expectArray]: T; result: ExtendsExcludingAnyOrNever<T, any[]>}
export type ExpectArray<T> = {
[expectArray]: T
result: ExtendsExcludingAnyOrNever<T, any[]>
}

/**
* @internal
*/
const expectSymbol = Symbol('expectSymbol')
export type ExpectSymbol<T> = {[expectSymbol]: T; result: ExtendsExcludingAnyOrNever<T, symbol>}
export type ExpectSymbol<T> = {
[expectSymbol]: T
result: ExtendsExcludingAnyOrNever<T, symbol>
}

/**
* @internal
Expand All @@ -143,7 +173,19 @@ export type ExpectNever<T> = {[expectNever]: T; result: IsNever<T>}
* @internal
*/
const expectNullable = Symbol('expectNullable')
export type ExpectNullable<T> = {[expectNullable]: T; result: Not<StrictEqualUsingBranding<T, NonNullable<T>>>}
export type ExpectNullable<T> = {
[expectNullable]: T
result: Not<StrictEqualUsingBranding<T, NonNullable<T>>>
}

/**
* @internal
*/
const expectBigInt = Symbol('expectBigInt')
export type ExpectBigInt<T> = {
[expectBigInt]: T
result: ExtendsExcludingAnyOrNever<T, bigint>
}

/**
* Checks if the result of an expecter matches the specified options, and
Expand Down
5 changes: 5 additions & 0 deletions test/__snapshots__/errors.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -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<number>' 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<string | number>().toMatchTypeOf<number>()
Expand Down
10 changes: 10 additions & 0 deletions test/usage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand All @@ -96,6 +97,9 @@ test('`.toBe...` methods allow for types that extend the expected type', () => {

expectTypeOf<boolean>().toBeBoolean()
expectTypeOf<true>().toBeBoolean()

expectTypeOf<bigint>().toBeBigInt()
expectTypeOf<0n>().toBeBigInt()
})

test('`.toBe...` methods protect against `any`', () => {
Expand Down Expand Up @@ -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', () => {
Expand Down Expand Up @@ -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', () => {
Expand Down

0 comments on commit 95f442b

Please sign in to comment.