diff --git a/README.md b/README.md index 886712dd76..5b1164fed1 100644 --- a/README.md +++ b/README.md @@ -811,6 +811,7 @@ isBoolean(value); | `@IsString()` | Checks if the value is a string. | | `@IsNumber(options: IsNumberOptions)` | Checks if the value is a number. | | `@IsInt()` | Checks if the value is an integer number. | +| `@IsBigInt()` | Checks if the value is a bigint number. | | `@IsArray()` | Checks if the value is an array | | `@IsEnum(entity: object)` | Checks if the value is a valid enum | | **Number validation decorators** | diff --git a/src/decorator/decorators.ts b/src/decorator/decorators.ts index d449e9301a..1ce4c1a4c9 100644 --- a/src/decorator/decorators.ts +++ b/src/decorator/decorators.ts @@ -121,6 +121,7 @@ export * from './string/is-iso4217-currency-code'; // Type checkers // ------------------------------------------------------------------------- +export * from './typechecker/IsBigInt'; export * from './typechecker/IsBoolean'; export * from './typechecker/IsDate'; export * from './typechecker/IsNumber'; diff --git a/src/decorator/typechecker/IsBigInt.ts b/src/decorator/typechecker/IsBigInt.ts new file mode 100644 index 0000000000..6742a00f14 --- /dev/null +++ b/src/decorator/typechecker/IsBigInt.ts @@ -0,0 +1,27 @@ +import { ValidationOptions } from '../ValidationOptions'; +import { buildMessage, ValidateBy } from '../common/ValidateBy'; + +export const IS_BIGINT = 'isBigInt'; + +/** + * Checks if the value is a bigint + */ +export function isBigInt(val: unknown): val is bigint { + return typeof val === 'bigint'; +} + +/** + * Checks if the value is a bigint + */ +export function IsBigInt(validationOptions?: ValidationOptions): PropertyDecorator { + return ValidateBy( + { + name: IS_BIGINT, + validator: { + validate: (value, args): boolean => isBigInt(value), + defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be a bigint number', validationOptions), + }, + }, + validationOptions + ); +} diff --git a/test/functional/validation-functions-and-decorators.spec.ts b/test/functional/validation-functions-and-decorators.spec.ts index 78ceddcd6d..9d29b08b2c 100644 --- a/test/functional/validation-functions-and-decorators.spec.ts +++ b/test/functional/validation-functions-and-decorators.spec.ts @@ -67,6 +67,7 @@ import { ArrayNotContains, ArrayUnique, IsArray, + IsBigInt, IsDateString, IsInstance, IsPhoneNumber, @@ -79,6 +80,7 @@ import { isDefined, isNumber, isURL, + isBigInt, isBoolean, isString, isInt, @@ -757,6 +759,40 @@ describe('IsInt', () => { }); }); +describe('IsBigInt', () => { + // By casting bigints via function instead of `2n` annotation we can avoid + // to bump the typescript build target from es2018 to es2020 + const validValues = [BigInt(2), BigInt(4), BigInt(100), BigInt(1000)]; + const invalidValues = ['01', '-01', '000', '100e10', '123.123', ' ', '', 10, 2.5, -0.1]; + + class MyClass { + @IsBigInt() + someProperty: string; + } + + it('should not fail if validator.validate said that its valid', () => { + return checkValidValues(new MyClass(), validValues); + }); + + it('should fail if validator.validate said that its invalid', () => { + return checkInvalidValues(new MyClass(), invalidValues); + }); + + it('should not fail if method in validator said that its valid', () => { + validValues.forEach(value => expect(isBigInt(value)).toBeTruthy()); + }); + + it('should fail if method in validator said that its invalid', () => { + invalidValues.forEach(value => expect(isBigInt(value as any)).toBeFalsy()); + }); + + it('should return error object with proper data', () => { + const validationType = 'isBigInt'; + const message = 'someProperty must be a bigint number'; + return checkReturnedError(new MyClass(), invalidValues, validationType, message); + }); +}); + describe('IsString', () => { const validValues = ['true', 'false', 'hello', '0', '', '1']; const invalidValues = [true, false, 1, 2, null, undefined];