number
Flow中的内置类型允许“外来”值,例如Infinity
,-Infinity
和NaN
.
如何强制类型只允许实数?
编辑。这不是如何检查变量是否为实数的问题。这是关于用 Flow 打字的。
我正在寻找编写函数的方法,例如:
// @flow
function sum (x: real, y: real) { ... }
我的问题是如何定义类型real
以便它与 Flow ( http://flowtype.org/ ) 一起使用。
number
Flow中的内置类型允许“外来”值,例如Infinity
,-Infinity
和NaN
.
如何强制类型只允许实数?
编辑。这不是如何检查变量是否为实数的问题。这是关于用 Flow 打字的。
我正在寻找编写函数的方法,例如:
// @flow
function sum (x: real, y: real) { ... }
我的问题是如何定义类型real
以便它与 Flow ( http://flowtype.org/ ) 一起使用。
使用 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 没有任何工具可以将某些值列入黑名单,同时允许其他相同类型的值。您只能将值列入白名单,包括使用并集和交集。
您可以使用 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!