網站搜尋

javascript - 如何宣告排除無限大和 NaN 的數字 Flow 類型?


Flow 中的內建類型 number 允許像 Infinity、-Infinity 和 NaN 這樣的「特殊」值。

我如何強制類型只允許實數?

編輯。這不是關於如何檢查變數是否為實數的問題。這是關於使用 Flow 進行類型標註的問題。

我正在尋找像這樣編寫我的函數的方法:

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

我的問題是如何定義類型 real 以使其能與 Flow (http://flowtype.org/) 一起使用。

答案#1

你不能用 Flow 來做到這一點。你需要運行時檢查。

在此查看有關實數問題的討論:https://github.com/facebook/flow/issues/1406

總而言之,幾乎對實數進行的任何運算都可能導致無窮大,因此區分實數和 NaN/無窮大並不是很有用,因為它可能返回一種類型,不能保證是實數。

例如,

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 並沒有任何功能可以在允許同種類型其他值的同時黑名單某些值。你只能白名單值,包括使用聯集和交集。

答案#2

在這方面,你可以和 Flow 達成一點中間地帶。是的,最終你需要使用運行時檢查來實現這一點,但你可以構建一個不透明類型,讓 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 = 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!