Git Product home page Git Product logo

Comments (19)

skatcat31 avatar skatcat31 commented on May 7, 2024 3

I'm confused why this code would even use !isNaN(x) since NaN == false. That parsing isn't needed. Because 0 is a number. However to check if something is a number you need to do some coercion checking to make sure. If it's coerced form is equal to it's numerical form then it is a number. Really what we want are more test cases that would be considered valid or invalid:

Tests

validateNumber('10') // true
validateNumber(false) // false
validateNumber(true) // false
validateNumber(10) // true
validateNumber(0.10) // true
validateNumber(010) // true
validateNumber(0xA) // true
validateNumber(NaN) // false
validateNumber(null) // false
validateNumber(undefined) // false
validateNumber('10%') // false, % is a construct
validateNumber('10px') // false
validateNumber(Infinity) // false
validateNumber(Math.PI) // true, but is such an extreme edge case...
validateNumber(0) // true, will probably wreck things
validatenumber(1e10) // true

test based coding is really the only way to infallible say "This method is complete to the best of my knowledge". As new tests fail that should be valid we then know the code is invalid. Fix, iterate, evolve.

Possible Code

const validateNumber = n => !isNaN(parseFloat(n)) && isFinite(n) && Number(n) == n;

Tested Possible Code

Notice negating on false cases. I should expect an entire array of true
image

EDIT:
Test cases now include an exponential notation number ~ skatcat

from 30-seconds-of-code.

atomiks avatar atomiks commented on May 7, 2024 2

@elderhsouza

validateNumber('20px') // true

from 30-seconds-of-code.

ephys avatar ephys commented on May 7, 2024 2

@Chalarangelo I definitely agree, parsing numbers in javascript is a pain with so many corner cases I lost count (which is why I restrict to usually restrict to strings/numbers and use Number to parse instead of parseFloat).

By the way the reason the solution works for most cases is that you're using two different kind of number conversions that happen to exclude the wrong results of each other. If it helps I made a document comparing the possible parsing methods to try and figure out the mess: https://gist.github.com/Ephys/4d9731d5c7a945dcc752d279eaeaa08f

from 30-seconds-of-code.

atomiks avatar atomiks commented on May 7, 2024 1

@fesebuv I believe the function is meant to allow a number string as well.

Also OP, what about booleans?

const validateNumber = n => isFinite(n)
validateNumber(true) // true

If it's meant to be an actual number, then Number.isFinite() should suffice. However, I thought the purpose was to also allow a string as input which makes it more useful when grabbing, for example, text from an input/textarea or an element attribute.

from 30-seconds-of-code.

elderhsouza avatar elderhsouza commented on May 7, 2024 1

@atomiks @fesebuv @Chalarangelo

I think this would do:

const validateNumber = n => isFinite(parseFloat(n))

from 30-seconds-of-code.

Chalarangelo avatar Chalarangelo commented on May 7, 2024

I think I based the snippet on this SO answer. It might be outdated or there might be something I don't understand. Does anyone know of any cases where Number.isFinite() alone would fail?

from 30-seconds-of-code.

fesebuv avatar fesebuv commented on May 7, 2024

🤔 what about?

const validateNumber = n => typeof n === 'number';

from 30-seconds-of-code.

Chalarangelo avatar Chalarangelo commented on May 7, 2024

Yes, the function is meant to allow strings containing numerical data, such as '10' for example, to evaluate to true. @elderhsouza I think this should probably work as intended. Can anyone find any test cases that break this? Otherwise, we should get a PR going and change the current solution to this.

from 30-seconds-of-code.

Chalarangelo avatar Chalarangelo commented on May 7, 2024

@atomiks technically speaking '20px' is a numeric value in CSS. 😛

from 30-seconds-of-code.

elderhsouza avatar elderhsouza commented on May 7, 2024

@Chalarangelo @atomiks

I'm using this to test the cases, and to be fair I now think @Chalarangelo was right all along, the first option doesn't break with any test cases so far:

isNumber = n => !isNaN(parseFloat(n)) && isFinite(n)

test = [Infinity, NaN, -Infinity, 0, 2e64, 910, null, '0', undefined, true, '20px', 50, '0xFFFFFF', 0xFFFFFF, '0xfff']
results = test.map(isNumber)

console.table([test, results])

from 30-seconds-of-code.

Chalarangelo avatar Chalarangelo commented on May 7, 2024

I told you guys where I think I found the original, but the clarification why it works is unclear on SO. Can anyone figure it out and explain it better so we can update the snippet's description?

from 30-seconds-of-code.

ephys avatar ephys commented on May 7, 2024

isNumber([1]) returns true. Any object that can be coerced into a number will return true too

I think the only safe way to do it is to explicitly whitelist numbers & strings

isNumber = n => {
  const type = typeof n;
  if (type !== 'string' && type !== 'number') {
    return false;
  }

  return isFinite(n);
}

Edit 1: Beware of toPrimitive and toString too:

obj = {
  [Symbol.toPrimitive](hint) {
    if (hint === 'string') {
      return '10';
    }

    if (hint === 'number') {
      return 10;
    }


    return true;
  }
};

isNumber(obj); // true

obj = {
  toString() {
    return '10';
  }
};

isNumber(obj); // true

Edit 2: Forgot valueOf but it only is called when converting using Number, not parseFloat

from 30-seconds-of-code.

Chalarangelo avatar Chalarangelo commented on May 7, 2024

@ephys isNumber([1,2]) returns false, though. I mean an array with just one number sounds reasonably valid to me, as parseFloat([1]) will work properly. JS is weird when it comes to stuff like this.

from 30-seconds-of-code.

ephys avatar ephys commented on May 7, 2024

@Chalarangelo That's due to coercion (the array is stringified into '1' then parsed as an int -- notice how parseFloat([1,2]) works too for the same reason) and that has caused more bugs than I can ever count. But if you want to consider arrays and above to be numbers it's up to you and likely depends on what you're trying to achieve :)

from 30-seconds-of-code.

Chalarangelo avatar Chalarangelo commented on May 7, 2024

@ephys you make a pretty good point. This can cause trouble, but limiting to specific data types can be troublesome as well. Generally the parsing system of JS is terrible, I mean parseFloat('123I am a little lamb') returns 123 for no apparent reason. I know why it works and I know this is the defined behavior, but I hate it and there are so many edge-cases that this whole thing becomes a nightmare to deal with.

In general, I agree, numbers and strings that can be converted to numbers should be considered valid by the implemented function (unless the are equal to Infinity), except that some strings that evaluate to numbers are not really numbers and we need to deal with those, I suppose.

from 30-seconds-of-code.

fesebuv avatar fesebuv commented on May 7, 2024

@atomiks @elderhsouza
in that case:

const validateNumber = n => parseInt(n, 10) =>  typeof n === 'number';

from 30-seconds-of-code.

Chalarangelo avatar Chalarangelo commented on May 7, 2024

@ephys that's a lot of effort you put in, but unfortunately I am too tired to read through the whole thing right now. First thing in the morning, though. I really want to figure out what to do with this specific snippet as I expect it to be used by a lot of people.

@fesebuv this still returns true for '20px', so it's not right yet.

from 30-seconds-of-code.

Chalarangelo avatar Chalarangelo commented on May 7, 2024

Resolved in #101 as suggested. If any problems arise, comment below to reopen the issue.

from 30-seconds-of-code.

lock avatar lock commented on May 7, 2024

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for any follow-up tasks.

from 30-seconds-of-code.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.