如何为不包括无穷大和NaN的数字声明Flow类型?

时间:2016-05-17 08:00:09

标签: javascript types typechecking flowtype

The built-in type number in Flow允许"异国情调" Infinity-InfinityNaN等值。

如何将类型强制为仅允许实数?

EDIT。 这是一个如何检查变量是否为实数的问题。 这是关于使用Flow打字。

我正在寻找编写我的函数的方法,如:

// @flow
function sum (x: real, y: real) { ... }

我的问题是如何定义类型real,以便它适用于Flow(http://flowtype.org/)。

2 个答案:

答案 0 :(得分:3)

使用Flow无法做到这一点。你需要运行时检查。

请在此处查看有关实数问题的讨论:https://github.com/facebook/flow/issues/1406

底线是,几乎所有对实数的操作都可能导致无穷大,因此区分实数和NaN / Infinity不会非常有用,因为它会返回一个类型,而不是保证是真实的。

例如,

Number.MAX_VALUE + Number.MAX_VALUE === Infinity
-Number.MAX_VALUE - Number.MAX_VALUE === -Infinity
Number.MAX_VALUE * 2 === Infinity
Number.MAX_VALUE / 0.5 === Infinity

与该讨论分开,Flow没有任何设施来黑名单某些值,同时允许相同类型的其他值。您只能白名单值,包括使用联合和交叉点。

答案 1 :(得分:0)

有一些中间立场你可以使用Flow进行攻击。是的,您最终需要使用运行时检查来解决此问题,但您可以构造一个opaque类型,让Flow强制执行您无法绕过这些验证功能。首先,在一个文件中,输入:

// @flow

// Define `Int` as an opaque type.  Internally, it's just a number.
// It's opaque because only this module can produce values of
// this kind, so in order to obtain an "Int", one _must_ use one of
// these functions, which (at runtime) will guarantee that these
// will always be integers.
export opaque type Int = number;

// Here's a function that will convert any number to an Int by running
// a typecheck at runtime and perhaps change the value (by rounding)
// This is the ONLY way of obtaining a value of the type Int   
export function int(n: number): Int {
    if (!Number.isFinite(n)) {
        throw new Error('Not a (finite) number');
    }

    // Round any real numbers to their nearest int
    return Math.round(n);
}

// In your private functions, you can now require Int inputs
export function isPrime(n: Int): boolean {
    // In here, you can assume the value of `n` is guaranteed to be an Integer number
    for (let i = 2; i < Math.sqrt(n); i++) {
        if (n % i === 0) return false;
    }
    return true;
}

然后,您可以使用以下内容:

// @flow

import { int, isPrime } from './lib';

isPrime(int(NaN));   // ok, but a runtime error, because NaN is not a number!
isPrime(int(3.14));  // ok, will effectively become isPrime(3)
isPrime(3.14);       // Flow error!