-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
isNaN
and isFinite
should accept number or string
#4002
Comments
The same is true of many other functions -- What's some example code where you'd intentionally pass a non-number to those functions? |
At the very least it should allow a string. if (position == 'right' || (isFinite(position) && position < 0)) { If Edit: I would make the same argument for Math.max, et al. |
That sort of unintended coercion I see as one of the major use cases for TypeScript, as there is just too much "flexibility" in ES. I personally would much prefer to throw an error and then for me to explicitly coerce it. It make my code more explicit. While technically it isn't needed at runtime, that is almost the whole point of TypeScript, isn't it? |
Implicit coercions are the bane of JavaScript. 99% of the 'wat' things people make fun of JS for are implicit coercions. Thinking about
Just because a function produces a result doesn't mean that result is a meaningful one. These are the kind of patterns we'd prefer to error on. There's a single-character fix: |
I agree with both of you, but I would suggest it's a matter of degree. Let's ignore
|
isNaN
and isFinite
should accept any valueisNaN
and isFinite
should accept number or string
+"2" // => 2
1+"2" // => "12" Tell me how this is more explicit or clear. JavaScript is the worst. |
Well, that is why I don't like the simplified coercions... I prefer to use the more explicit: Number("2"); // => 2
1 + Number("2"); // => 3 Because of exactly that... No one is going to get confused (including the runtime) about what I am trying to do, including myself. More typing, sure... but far less surprising. |
My thinking is that in the case of if (isFinite(y)) { x += Number(y); }
if (isFinite(Number(y))) { x += Number(y); } I guess I just don't really see what the second line buys you over the first, at least as far as |
Unary The real problem here is that calling |
I realized I should be using a type guard instead. There's no need to coerce anything because I always know what the type is. |
I disagree with closing this issue @RyanCavanaugh @kitsonk @DanielRosenwasser. Here's a valid usecase: Object.keys(whatever).filter(isNaN) // filter out numbered indices That doesn't work because Object.keys(whatever).filter(Number) // filter out anything but numbered indices Both of these patterns are extremely useful when iterating enums, for example, which have both keyed numbered indices. Please reconsider, P.S. Object.keys(whatever).filter(k => isNaN(Number(k))); But that unnecessarily ugly and verbose. This isn't Java. |
Can't you overload the declaration of function isNaN(anything:any):boolean; // this doesn't emit anything
⋮
Object.keys(whatever).filter(isNaN); // but this typechecks now This gives you the behavior you want without imposing that decision onto those who prefer |
After looking more at These functions return sensible values for things which are
|
@RyanCavanaugh There are some extremely valid usecases for While I agree that isNaN does some crazy voodoo to get the argument to be a number (like your example with the array), it does make sense to be able to check the NaNness of strings specifically. Also, your point with the array is irrelevant since it would still happen with direct conversion:
I probably, could, I hadn't thought of that. But then again, I still maintain that it makes more sense for isNaN's accept type to be |
Fundamentally, |
@darrylring No, that's not what Had I wanted to force only number values, I'd use |
@MadaraUchiha, what do you expect the output of var arr = ['','0B0','0E0','0O0','0X0','0.0','000','9E-999'];
console.log(arr.filter(isNaN));
console.log(arr.filter(Number)); to be? |
That's not entirely fair, given how all of those evaluate to 0, which is a falsey value. That's not the point being made here. Note that again the protection that TypeScript gives you here is moot since |
Your main use case is something like separating out the numeric and non-numeric keys of an object, right? I don't think The function Side note: I don't think This is all just my opinion, obviously. I was just trying to understand the use case. |
Added a FAQ entry |
According to the ES5.1 spec (15.1.2.4, 15.1.2.5),
isNaN(number)
andisFinite(number)
perform theToNumber(number)
abstract operation before checking ifnumber
coerces toNaN
or±Infinity
.To me, this implies that the argument to these functions can be any type. I think TypeScript should follow this as well. Why check if a variable is a number before checking if it's not a number (NaN)? Why manually coerce a variable into a number before calling a function that, according to the specification, does just that?
The text was updated successfully, but these errors were encountered: