class-validator
class-validator copied to clipboard
IsNumber decorator fails on values ABS(x) < 0.000001
Hi team,
IsNumber
decorator throws error, when a small value is analyzed (ABS(x) < 0.000001. It happens because such a small value has exponential format -->
> parseFloat('0.000001')
< 0.000001
> parseFloat('0.0000001')
< 1e-7
The following code fails, because value.toString().split('.')[1]
is not available - there's no .
in the string!
if (options.maxDecimalPlaces !== undefined) {
let decimalPlaces = 0;
if (value % 1 !== 0) {
decimalPlaces = value.toString().split('.')[1].length;
}
if (decimalPlaces > options.maxDecimalPlaces) {
return false;
}
}
https://github.com/typestack/class-validator/blob/2ef8ff0f32be53e75dade2a0b86b158d87427176/src/decorator/typechecker/IsNumber.ts#L34
A fix proposal (I wasn't allowed to create a pull request for some reason, sorry)
if (options.maxDecimalPlaces !== undefined) {
let decimalPlaces = 0;
if (value % 1 !== 0) {
const stringValue = value.toString();
if (stringValue.indexOf('.') > -1){
decimalPlaces = stringValue.split('.')[1]?.length ?? 0;
}
else if (stringValue.indexOf('e-') > -1) {
decimalPlaces = parseInt(stringValue.split('e-')[1] ?? '0');
}
}
if (decimalPlaces > options.maxDecimalPlaces) {
return false;
}
}
All the indexOf and split stuff seems very arcane for number manipulation. Is there no better, numeric way to get the decimal places?
@Clashsoft I'm afraid, there is no reliable, numeric way to determine how many digits are present in the fractional part. Theoretically, we should be able to simply multiply the value by 10 until we get an integer, but as we all know, float operations may end up with an unexpected result and it won't work in some cases.