1

Can anyone tell me what typescript error here?

public sortList<T>(data: T[], key: string, action: boolean): Observable<T[]> {

const outputData: T[] =  data.sort((a, b) => {
  if (isNaN(a) && isNaN(b)) {
    return a[key].toUpperCase() > b[key].toUpperCase() ? 1 : a[key].toUpperCase() < b[key].toUpperCase() ? -1 : 0;
  }
});

return of(outputData)
  .pipe(
    share()
  );
}
}

isNaN(a) and >isNaN(b) is throwing following error.

(parameter) b: T
Argument of type 'T' is not assignable to parameter of type 'number'.ts(2345)
Marek Urbanowicz
  • 12,659
  • 16
  • 62
  • 87
gauti
  • 1,264
  • 3
  • 17
  • 43
  • 1
    Presumably, TS has the wrong type for the parameter of `isNaN` - it doesn't only accept numbers, it can take any value. Or maybe it was an intentional design - if you only pass numbers to `isNaN` you actually avoid the pitfalls of it. At any rate, it doesn't seem like you want `isNaN` - if you just want to check if it's a number or not, then try `typeof a === "number"` – VLAZ Aug 14 '19 at 07:11
  • 1
    Can you provide any example of what are you trying to achieve? This is really strange function so would be nice to get better understanding of what you are doing so then we can help you – Marek Urbanowicz Aug 14 '19 at 07:15
  • @MU. am invoking this function for sorting a list which has string ("test")and number as string("1234.23"). so I would like to sort accordingly. so before that I need to check isNaN or not – gauti Aug 14 '19 at 07:21
  • @gauti but then you are better off converting to number yourself and passing to `isNaN`. It's what the function does anyway - `isNaN(+a)` EDIT: although the sorting is still odd - `a` and `b` are supposed to be *objects*, so checking them for `isNaN` is still odd. – VLAZ Aug 14 '19 at 07:28
  • @VLAZ. I Got your point, But am writing generic code. so i can't go and handle in each and every function. – gauti Aug 14 '19 at 07:31
  • @gauti well, `isNaN` literally just checks if the argument you pass in *when converted to a number* will produce `NaN`. So if you do the conversion step yourself, you don't subvert what `isNaN` would produce. If your expectation is to check if the argument is a number or not, then it can still produce a false negative `+true === 1`, so `isNaN(true) === false`. Similarly, `+"" = 0` (empty string), thus `isNaN("") === false`. Changing those to `isNaN(+true)` and `isNaN(+"")`, etc., wouldn't change the behaviour at all. – VLAZ Aug 14 '19 at 07:36

1 Answers1

1

Using the juggly-version of isNaN is discouraged, though I can see that you're using it to check both type and NaN in your case. While this works with a bit of juggling, it is better to be a bit more belt-and-braces and use type checking to check types, and NaN checking to check NaNs.

The first chunk of console logs (1 - 3) are showing you the behaviour you are using from isNaN. I use the (inverted) equivalents of type checks in the next section (4 - 6).

The final bit (7 - 8) shows the use of type-and-NaN checking. At this stage, you aren't relying on the sketchy behaviour of isNaN and can use either the global version (as you are now certain you are using a number) or the Number.isNaN version, which is tighter.

The belt-and-braces version has no compiler warnings.

const num = 1;
const str = 'string';
const obj = { key: 'value' };

// Technically works, but compiler warnings

console.log('1.', isNaN(num)); // false
console.log('2.', isNaN(str)); // true
console.log('3.', isNaN(obj)); // true

// A bit more type-ish (note the results are inverted as I'm showing the "positive" test

console.log('4.', typeof num === 'number'); // true
console.log('5.', typeof str === 'number'); // false
console.log('6.', typeof obj === 'number'); // false

const a = 1;

if (typeof a === 'number') {
    console.log('7a.', isNaN(a)); // false
    console.log('7b.', Number.isNaN(a)); // false
}

const b = NaN;

if (typeof b === 'number') {
    console.log('8a.', isNaN(b)); // true
    console.log('8b.', Number.isNaN(b)); // true
}

Here is a version that sorts out the strings from the numbers:

function stringNumberCheck(strNum: string | number) : boolean {
    const numeric = +strNum;
    return (typeof numeric === 'number' && !Number.isNaN(numeric));
}

console.log('1:', stringNumberCheck(1)); // true
console.log("'100':", stringNumberCheck('100')); // true
console.log("'Hello':", stringNumberCheck('Hello')); // false

Demo

"use strict";
function stringNumberCheck(strNum) {
    const numeric = +strNum;
    return (typeof numeric === 'number' && !Number.isNaN(numeric));
}
console.log('1:', stringNumberCheck(1)); // true
console.log("'100':", stringNumberCheck('100')); // true
console.log("'Hello':", stringNumberCheck('Hello')); // false
Fenton
  • 241,084
  • 71
  • 387
  • 401
  • There is still a slight potential problem - `stringNumberCheck("")` will return `true`, when the value is actually *not* a number. Or not necessarily a number - perhaps it's fine to treat it as zero, perhaps not. It's still a potential pitfall that is worth mentioning. There is [also this old question on validating numbers](https://stackoverflow.com/questions/18082/validate-decimal-numbers-in-javascript-isnumeric) – VLAZ Aug 14 '19 at 09:57
  • @VLAZ that's true, an empty string would effectively be treated as zero. – Fenton Aug 16 '19 at 12:18