TypeScript的isNaN函数只接受一个数字作为参数

102

我使用的是 WebStorm 2016.2.2、TypeScript 2.1 和 Node.js。

由于某种原因,isNaN 被声明为只接受数字的函数:

declare function isNaN(number: number): boolean;
我尝试将它改为任何类型,但似乎对TSC没有影响。我仍然得到相同的错误提示:

参数类型为“字符串”的值无法分配给类型为“数字”的参数

我的代码(简化版):

isNaN("10");

我该如何解决/规避这个问题?


编辑:

需要注意的是,根据规范,isNaN的参数可以是任何类型:Number.isNaN()

另外:我的代码已经被简化了。实际上,我会收到一个可能是字符串或数字的参数,如果它是字符串,它可能是我想要转换为数字的字符串数字(“10”),也可能是一个简单的字符串(“Hello world”)。

我不想包含整个代码以避免让问题变得太长,但因为它引起了混乱,所以这是我的真实代码:

            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;
            }

3
通常你会将一个表达式传递给 isNaN() 方法来判断该表达式的结果是否为数字。传递字面量有些多余,你认为呢? - Scott Marcus
1
@NitzanTomer 我并不真正检查一个字面量是否为NaN,我简化了我的代码。无论如何,根据规范,isNan应该接受任何类型。 - Alon
但是如果你正在使用 TypeScript,那么你如何会发现自己处于传递除 numberany 以外的任何东西的情况下呢? - Nitzan Tomer
它可以与 any 一起使用:let a: any = "str"; console.log(isNaN(a)); 在编译器中是可以的,事实上这也是可以的:isNaN("str" as any) - Nitzan Tomer
1
@NitzanTomer 就像你调用 parseInt 和 parseFloat 一样,它们明确要求一个字符串。有时候,除非你将数据放在正确的格式/类型中,否则它可能不会处于正确的格式/类型。 - Daniel
显示剩余4条评论
8个回答

94

我建议你采用不同的代码实现方式。
原因如下:

  1. 这段代码可能很短,但很难理解其中的逻辑。
  2. 在这里使用 isNaN 不是最佳选择:isNaN("") 也会返回 false

最好尝试将值转换为数字并检查其是否为 NaN (与 @smnbbrv 所述相同):

if (typeof expectedValue === "string" && !Number.isNaN(Number(expectedValue))) {
    expectedValue = Number(expectedValue);
}

编辑

你可以将你的值传递为 any 类型:

isNaN(ctualValue as any)
为了绕过编译器检查。

1
你的问题属于所谓的XY问题,这就是为什么所有的答案/评论都关注于你对isNaN的使用。我已经更新了我的回答以满足你的需求。 - Nitzan Tomer
谢谢。我按照你的建议修改了我的代码。你是对的,这是一个XY问题。我不知道一个空字符串会返回false。 - Alon
我参考了 https://dev59.com/qXVC5IYBdhLWcg3w0EoD#175787 关于 isNaN 可以接受不仅仅是数字的有效性。 - Jono
2
as any 得到了加分。 - Andre Elrico
8
因为Number("")的结果是 0,所以isNaN(Number(""))仍然返回false...... - Neil
将值作为“任意类型”传递并不能满足我的编译器。我使用了isNaN来防止数据加载时出现NaN闪烁。传递isNaN(value as unknown as number)就是解决方案。 在我的情况下,percentageTotal={isNaN(percentageTotal as unknown as number) ? "0" : percentageTotal}。如果在数据加载时有一个加载器,也可以解决这个问题,但现在我可以自由地显示空图表,以获得良好的视觉效果。感谢@NitzanTomer解决了一些TS问题。 - tralawar

27

你不应该解决这个问题,因为这就是TypeScript的工作方式。

先将输入转换为数字类型。

Number("10") // 10
Number("abc") // NaN

然后使用isNan函数检查结果:

isNaN(Number("abc"))

2
通常建议避免使用Number()String()Boolean()函数,最好使用parseInt()parseFloat() - Scott Marcus
4
@ScottMarcus,您可能在谈论new Number(),通常应该避免使用它(因为它会创建对象而不是字面量),并且如果我没记错的话,在ES6中已经弃用了它;但是 Number() 没有任何问题。如果有问题,请澄清一下。 - smnbbrv
2
请说明为什么这是不好的。我经常使用它,没有任何问题。我并不是在告诉你错误;我真的想知道如果这是一个不好的实践来改善我的代码。 - smnbbrv
2
@ScottMarcus 不是 parseInt('0x11') 也会返回17吗? - Paarth
3
@Paarth,是的,但是你永远不应该在没有radix的情况下使用parseInt函数——parseInt('0x11') // => 17parseInt('0x11', 10) // => 0相比。 - Mulan
显示剩余9条评论

3

具有讽刺意味的是,只有数字可以是NaN,所以您需要先将字符串转换为数字。

一个非常简单的方法是使用一元加操作符。

因此,您可以进行简单的isNaN(+"10")

请记住,像+""+" "+"\n"这样的东西都是0!


1
首先,只有类型为number的值才能是NaN。因此,如果静态上下文告诉您该值的类型为string,您可以确定它不是NaN。如果您有一个类型为string|number的值(顺便说一句,应该避免这种情况),您仍然可以决定如何处理它。严格来说,字符串值"foo"不是NaN,因为NaN是IEEE标准中指定的浮点数的特定值。但在javascript中,isNaN("foo")将为true,因为该函数将首先将字符串强制转换为数字,而该强制转换结果为NaN。Typescript试图利用类型,在您不应使用isNaN的地方防止您使用它。

1
传递 isNaN(value as unknown as number) 可满足我的编译器。 在我的情况下,我使用 isNaN() 来防止数据加载时出现 "NaN" 闪烁。这使我能够将一个 string 传递到 isNaN() 中,因为接口预期是一个字符串。

1
在被接受的答案中,!Number.isNaN(Number(expectedValue)) 对于空字符串('')和空格字符串(' ')仍然返回true。将它们转换为数字将导致0
我不是JavaScript开发人员,特别是从.Net来看,这对我来说看起来很疯狂,但这似乎是我所做的事情:
private static isNumber(value: any): boolean {
  return (typeof value === 'number' && !isNaN(value))
      || ((typeof value === 'string') && value.trim() != '' && !isNaN(Number(value)))
  }

如果您知道更合理的解决方案,请务必进行编辑!
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

0

在谷歌上找到了这个答案,并从这里的各种答案和评论中得出了我的答案;我的答案是使用:

isNaN(Number(string))

这将正确地告诉我字符串是否为数字。

我以前使用parseInt(),但如果字符串是像123abc这样的东西,它会失败,因为parseInt只会丢弃字母(有时很有用,但在这里不行)。

注意:我很高兴Number('')评估为零,但如果你不是,这不是解决方案!


0
你可以通过在isNaN内部使用parseInt来解决这个问题。如果parseInt返回NaN,检查isNaN仍然有效。这样你的TypeScript错误就会被解决。
if (typeof actualValue === "string" && !isNaN(parseInt(actualValue, 10))) {
  actualValue = +actualValue;
}

我不喜欢这个解决方案,因为它需要"浪费额外的 CPU 周期",而 isNaN 其实完全可以处理非数字类型。isNaN 不仅适用于检查数字是否为 "确切的 NaN",还适用于检查对象是否"不是数字"。使用 const x = n === undefined || n === null || isNaN(n) ? -1 : n,其中 const x = isNaN(n) ? -1 : n 只是浪费空间。 - mausworks
@diemaus,你认为isNaN函数是做什么的?它将非数字值转换为数字,这会“浪费额外的CPU周期”。但这样做只是显式地表达了出来。显式=好。 - Roberto Zvjerković

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接