TypeScript isNaN only accepts a number - javascript

I work with WebStorm 2016.2.2, TypeScript 2.1, Node.js.
For some reason, isNaN is declared as a function that only accepts a number:
declare function isNaN(number: number): boolean;
I tried to change it to any, but it looks like it doesn't influence on the TSC. I still get the same error:
Argument of type 'string' is not assignable to parameter of type
'number'
My code (simplified):
isNaN("10");
How can I solve/workaround it?
Edit:
Notice that according to specification, isNaN's parameter can be any type: Number.isNaN()
Also: My code was simplified. I actually receive a parameter that may be either a string or a number, and if it's a string it may be either a stringy number that I would like to convert to number ("10") or a simple string ("Hello world").
I didn't want to make this question long by including my entire code, but because it caused confusion, this is my real code:
if (typeof expectedValue === "string" && !isNaN(expectedValue)) {
expectedValue = +expectedValue;
}
if (typeof actualValue === "string" && !isNaN(ctualValue)) {
actualValue = +actualValue;
}
switch (this.operator) {
case Operator.equal:
return actualValue == expectedValue;
case Operator.notEqual:
return actualValue === undefined || actualValue != expectedValue;
case Operator.greaterThan:
return actualValue > expectedValue;
case Operator.littleThan:
return actualValue < expectedValue;
case Operator.greaterOrEqual:
return actualValue >= expectedValue;
case Operator.littleOrEqual:
return actualValue <= expectedValue;
}

I advise you to implement your code differently.
The reasons:
It might be short, but it's not easy to understand what's going on
Using isNaN isn't the best option here: isNaN("") returns false as well
You better try to convert the value into a number and check if that's NaN or not (as #smnbbrv wrote):
if (typeof expectedValue === "string" && !Number.isNaN(Number(expectedValue))) {
expectedValue = Number(expectedValue);
}
Edit
You can pass your value as any:
isNaN(ctualValue as any)
To bypass the compiler check.

You should not solve it because this is how TypeScript works.
Just cast the input to number first
Number("10") // 10
Number("abc") // NaN
and then check the result with the isNan function:
isNaN(Number("abc"))

As ironically only numbers can be NaN, you need to transform strings into numbers first.
A very simple way to do this is the unary plus operator.
So you can do a simple isNaN(+"10").
Keep in mind that thing like +"", +" " and +"\n" are 0!

First of all, only values of type number can be NaN. So if the static context tells you your value is of type string for example, you can be sure that it is not a NaN. If you have a value with type string|number (which should be avoided btw) you can still decide how you handle this. Strictly speaking, the string value "foo" is not NaN, as NaN is a specific value specified in the IEEE standard for float numbers. But still, in javascript, isNaN("foo") will be true, as the function will coerect the string to a number first, and that coerection results in a NaN. Typescript tries to take advantage of types here, it tries to prevent you from using isNaN where you should not.

You can solve this by using parseInt inside your isNaN. The check isNaN will still work if the parseInt returns NaN. And your Typescript error will be solved.
if (typeof actualValue === "string" && !isNaN(parseInt(actualValue, 10))) {
actualValue = +actualValue;
}

In the accepted answer, !Number.isNaN(Number(expectedValue)) still returns true for empty string ('') and whitespace strings (' '). And converting these to number will result in 0.
I'm not a JavaScript developer, and – especially coming from .Net – it looks insane to me as well, but this is what I've done that seems to work:
private static isNumber(value: any): boolean {
return (typeof value === 'number' && !isNaN(value))
|| ((typeof value === 'string') && value.trim() != '' && !isNaN(Number(value)))
}
If you know a saner solution, be sure to edit this!
console.log(isNumber([])); // false
console.log(isNumber({})); // false
console.log(isNumber("")); // false
console.log(isNumber(" ")); // false
console.log(isNumber(" 1 ")); // true <= note
console.log(isNumber(" 1 2")); // false
console.log(isNumber("1")); // true
console.log(isNumber(1)); // true

Found this answer from Google, and reached my answer from the various answers and comments here; my answer is to use:
isNaN(Number(string))
This will correctly tell me if the string is a number.
I was previously using parseInt(), but this fails if the string is something like 123abc as parseInt just discards the letters (useful sometimes, but not here).
Note: I'm happy that Number('') evaluates to zero, but if your not, this isn't the solution!

Passing isNaN(value as unknown as number) satisfied my compiler.
In my case, I was using isNaN() to prevent "NaN" from flashing while data loaded. This allowed me to pass a string into isNaN() since the interface expected a string.

Related

Is it good a good practice to stringify array?

Let's say I have an Array consist of Boolean.
myArray = [false,false,false]
And I will need to do different stuff according to every status.
ex :
[false,true,false], [false,false,true], [true,true,false], ...
and so on.
Usually this kind of operation is done by checking each individual element to see fit.
ex:
if(!myArray[0] && myArray[1] && !myArray[2]) do A
if(!myArray[0] && !myArray[1] && myArray[2]) do B
if(myArray[0] && myArray[1] && !myArray[2]) do C
...
Instead of doing that. I convert the array into String:
switch(JSON.stringify(myArray))
case : "[false,true,false]"
do A
break
case : "[false,false,true]"
do B
break
case : "[true,true,false]"
do C
break
......
Is this considered good practice? Is there any hidden error I might face with this method?
Will this method increase readability ?
About Using JSON.stringify
The use of JSON.stringify will work fine for arrays (of arrays (of arrays...)) of (JSON-compatible) primitives, i.e. boolean, string, number, null. There is no ambiguity. The ECMAScript specification also is clear about the "gap" to produce between distinct values: it should be the empty string, unless explicitly defined differently via the optional argument. See ECMAScript Language Specification on the topic.
One caveat is that undefined is not a thing in JSON, and so [null] and [undefined] would both be stringified to "[null]". But since you are only using false and true, this is not an issue.
Now to your questions:
Is this considered good practice?
That is a matter of opinion. My first intuition says "no", mainly because of the type conversion, but since there are no caveats for your particular use case (i.e. array of boolean), we cannot really have much to criticise about.
Is there any hidden error I might face with this method?
No
Will this method increase readability ?
Yes
There is however at least one alternative that has all the same advantages, but does not rely on some data type conversion:
Alternative: bitset
In case your array is an array of boolean, you can opt to use a numeric data type instead, where each binary bit of a number corresponds to a boolean in the array version.
It is to be expected that this method will be more efficient than the strinfigication option, because that data type conversion obviously takes some time.
Here is a run of the original array pattern:
let arr = [false, false, true];
if (!arr[0] && arr[1] && !arr[2]) console.log("do A");
if (!arr[0] && !arr[1] && arr[2]) console.log("do B");
if (arr[0] && arr[1] && !arr[2]) console.log("do C");
Here is the same logic implemented with a bitset:
let bitset = 0b001;
if (bitset === 0b010) console.log("do A");
if (bitset === 0b001) console.log("do B");
if (bitset === 0b110) console.log("do C");
If ever you need more bits than are available in the number data type (53 bits), then you can go for BigInt. For instance:
let bitset = 0b1010101010101010101010101010101010101010101010101010101n;
// A partial comparison
if ((bitset & 0b100010001n) === 0b100010001n) console.log("do A");
Of course, it is not necessary to use 0b literals; this is just to highlight the correspondence with the array version. You can save some characters by writing numbers in hexadecimal notation (0x) or even plain decimal, although the latter would be more obscure for the reader of your code.
Not much wrong with it per se, depends on the context; how many of these booleans are there, where do they come from / what sets them, how many cases, etc. Bad part could be that it can be very hard to understand what is happening and to debug, especially if you have 10+ values in there.
You could perhaps convert each boolean to a string/word that means something in that context, so you get a sentence. If you have a unique word for each boolean, you could leave out the false ones so you only have to write down certain combinations.
Also instead of JSON.stringify() you can use myArray.join(',') which outputs true,true,false (so without the brackets).
Your goal is to write a readable if?
Stringify is a solution, but (maybe only for me) it is a little bit strange.
Here is my advice. Write a function like this:
isEqual(left, right) {
if (left.length !== right.length) return false;
for (var i = 0; i < left.length; i++) {
if (left[i] !== right[i]) return false;
}
return true;
}
And use it like this:
if (isEqual(array, [true, false, true])) alert('isEqual');

how many ways to check if x is integer and which one is most efficient?

I already checked what is the best way to check variable type in javascript
question on So but didn't found answer of my question.
In javascript how many ways to find if input type is integer? which one is efficient?
I was looking the way to find the integer in javascript and found number of ways to do this:
Using typeof
function isInteger(x)
{
return (typeof x === 'number') && (x % 1 === 0);
}
console.log(isInteger(10));
console.log(isInteger(10.1))
Using parseInt
function isInteger(x)
{
return parseInt(x, 10) === x;
}
console.log(isInteger(10));
console.log(isInteger(10.1));
Using Math.round
function isInteger(x)
{
return Math.round(x) === x;
}
console.log(isInteger(10));
console.log(isInteger(10.1));
Is there any other way to find the type of Integer and which one will be most efficient for consider small to large integer values.
The most intuitive one is Number.isInteger(), at least in my opinion
function isInteger(x)
{
return Number.isInteger(x);
}
console.log(isInteger(10)); // Output: True
console.log(isInteger(10.1)); // Output: False
Edit
As for efficiency, I created a benchmark on jsben.ch where I try all your methods and mine, you can see for yourself ;)
Link
I just tested the speed of each code at JSBEN.CH
typeof => 347 ms
parseInt => 338 ms
Math.round => 367 ms
Interestingly, parseInt is the fastest way!
It's only the speed comparison. Go with Number.isInteger(x) instead! It's the instinctive & fastest of all.
Your propositions seem fine, but let's add for completion the polyfill Mozilla puts forward :
Number.isInteger = Number.isInteger || function(value) {
return typeof value === 'number' &&
isFinite(value) &&
Math.floor(value) === value;
};
I am concluding answer for this question after some resarch
From ECMAscript 6 which introduces a new Number.isInteger() function for precisely this purpose.
However, prior to ECMAScript 6, this is a bit more complicated, since no equivalent of the Number.isInteger() method is provided.
The simplest and cleanest pre-ECMAScript-6 solution (which is also sufficiently robust to return false even if a non-numeric value such as a string or null is passed to the function) would be the following use of the bitwise XOR operator:
function isInteger(x)
{
return (x ^ 0) === x;
}
Others like Math.round() ,typeof and parseInt can be used also to find the Integer.
While this parseInt-based approach will work well for many values of x, once x becomes quite large, it will fail to work properly. The problem is that parseInt() coerces its first parameter to a string before parsing digits. Therefore, once the number becomes sufficiently large, its string representation will be presented in exponential form (e.g., 1e+21). Accordingly, parseInt() will then try to parse 1e+21, but will stop parsing when it reaches the e character and will therefore return a value of 1.

Codecademy - Looking for clarification on syntax ( === "number" )

I'm working my way through the Codecademy 'Intro to JavaScript' course. I've just came across an example section of code that has confused me a little and doesn't seem to be explained. I've looked at the Mozilla documentation and think I understand but I'm really just looking for clarification on the subject.
let restaurant = {
_name: 'Italian Bistro',
_seatingCapacity: 120,
_hasDineInSpecial: true,
_entrees: ['Penne alla Bolognese', 'Chicken Cacciatore', 'Linguine
pesto'],
set seatingCapacity(newCapacity) {
if (typeof newCapacity === 'number') { // THIS LINE
this._seatingCapacity = newCapacity;
console.log(`${newCapacity} is valid input.`);
} else {
console.log(`Change ${newCapacity} to a number.`)
}
}
My question - Does 'number' here mean a number (12, 343 etc.) rather than the string 'number' in all cases? Or is it only within the typeof operator?
I'm assuming it's a silly question but it's one that threw me off. Thanks.
=== is used to check for strict equality. Consider the following example
0 == false //<== returns true
0 === false //<== returns false
In your example is not necessary, as typeof will never return any value that could be equal to number without being the number string itself. But it's considered good practice to use === (although I personally think it depends on what you are comparing)
(list of possible returned values for typeof here)
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof

Why are my test for checking floats keeps returning false?

I created a javascript method that checks if a number is a float. Each time I test the method for a float it keeps returning FALSE. I am not sure what I am doing wrong here. Any help would be really appreciated!
Below is my code.. Thanks!
function isFloat(n){
var patt = new RegExp('[+-]([0-9]*[.])?[0-9]+');
return patt.test(n)
}
console.log(isFloat(12.40));
There's a much easier way to check if a number is a float. Just compare the floored value against the original value. If they're the same, it's an integer.
function isFloat(n) {
return Math.floor(n) !== n;
}
console.log(isFloat(1));
console.log(isFloat(1.2));
console.log(isFloat(12));
console.log(isFloat(12.4));
This will work if, and only if, you only use it on numbers. You can perform an additional check if you're worried about someone passing in non-numbers.
function isFloat(n) {
return typeof n === 'number' && Math.floor(n) !== n;
}
Or you can simplify this even further by using Number.isInteger, provided you're running an environment that supports it.
function isFloat(n) {
return typeof n === 'number' && !Number.isInteger(n);
}
console.log(isFloat(1));
console.log(isFloat(1.2));
console.log(isFloat(12));
console.log(isFloat(12.4));
console.log(isFloat('a'));
Your RegEx is wrong, it should be
/[+-]?\d+\.\d+/g
Also, as others noted, this is not the best solution for this. Use !Number.isInteger(num)
The problem is that toString does not insert '+' before a number:
12.40.toString(); // "12.4", not "+12.4"
So you could use a regular expression like
new RegExp('[+-]?([0-9]*[.])?[0-9]+');
However, I recommend Validate decimal numbers in JavaScript - IsNumeric()

Why is angular.isNumber() not working as expected?

It appears as if AngularJS's angular.isNumber is not working. It doesn't work with strings that are numbers. Am I doing something wrong? Should I just use isNaN()?
angular.isNumber('95.55') == false
angular.isNumber('95.55' * 1) == true
angular.isNumber('bla' * 1) == true
angular.isNumber(NaN) == true
I need something to see if a string is a number (when it actually is) and angular.isNumber() won't let me do that unless I multiply by 1, but if I do that then it will always be true. Also NaN is not a number (by definition) and so should return false.
In JavaScript, typeof NaN === 'number'.
If you need to recognise a String as a Number, cast it to Number, convert back to String and compare this against the input, for example.
function stringIsNumber(s) {
var x = +s; // made cast obvious for demonstration
return x.toString() === s;
}
stringIsNumber('95.55'); // true
stringIsNumber('foo'); // false
// still have
stringIsNumber('NaN'); // true
I was working on the same problem and I was trying to work around that edge case. So I created a slightly different approach.
FIDDLE
function isStringNumber(str) {
var parsed = parseFloat(str);
var casted = +str;
return parsed === casted && !isNaN(parsed) && !isNaN(casted);
}
Use it as below,
angular.isNumber(eval('99.55'))
for other expressions also we may use eval(input).
Note: eval() is a javascript method
Edit:
It is not recommended to use eval(), as document says Never use eval()!
Thanks #Diogo Kollross

Categories

Resources