class-validator icon indicating copy to clipboard operation
class-validator copied to clipboard

feature: Range decorator for numbers

Open rastorc3v opened this issue 1 year ago • 2 comments

Description

There are two string length check decorators: @MinLength and @MaxLength. Additionally, there is a string decorator @Length(min, max) which checks if string length is in range between min and max.
As a developer, having @Min and @Max decorators for numbers, which works similar to @MinLength and @MaxLength, I would expect the third, @Range(min, max) decorator, to be delivered with class-validator.

Proposed solution

Create a new @Range decorator for numbers, which is a combination of Min and Max decorators.

Code implementation suggestion:

import { ValidationOptions } from '../ValidationOptions';
import { buildMessage, ValidateBy } from '../common/ValidateBy';

export const RANGE = 'range';

/**
 * Checks if the first number is greater than or equal to the second and less than or equal to the third.
 */
export function range(num: unknown, min: number, max: number): boolean {
  return typeof num === 'number' && typeof max === 'number' && typeof min === 'number' && min <= num <= max;
}

/**
 * Checks if the value is greater than or equal to the allowed minimum value and less than or equal to the allowed maximum value.
 */
export function Range(minValue: number, maxValue: number, validationOptions?: ValidationOptions): PropertyDecorator {
  return ValidateBy(
    {
      name: RANGE,
      constraints: [minValue, maxValue],
      validator: {
        validate: (value, args): boolean => range(value, args?.constraints[0], args?.constraints[1]),
        defaultMessage: buildMessage(
          eachPrefix => eachPrefix + '$property must be greater than or equal to $constraint1 and less than or equal to $constraint2',
          validationOptions
        ),
      },
    },
    validationOptions
  );
}

It would simplify code for typical use case like this:

@Min(1)
@Max(10)
priority: number

The same conditions with new decorator would look like this:

@Range(1, 10)
priority: number

rastorc3v avatar Nov 03 '24 19:11 rastorc3v

Take into account that there may be conflicts with using Range as a decorator name, as shown in the screenshots. This name is already associated with the Range interface in the DOM API, which could lead to confusion or potential conflicts.

image image

Possible alternatives:

@ValueRange()
@MinMaxRange()
@Between()
@WithinRange()

More on Range:

interface Range
A fragment of a document that can contain nodes and parts of text nodes.

https://developer.mozilla.org/en-US/docs/Web/API/Range

bzhn avatar Nov 07 '24 21:11 bzhn

Have nothing against name changing suggestion from @bzhn 👍. Will add another suggestion: @NumRange

rastorc3v avatar Nov 10 '24 20:11 rastorc3v