javascript - Bagaimana cara mendeklarasikan tipe Flow untuk angka yang mengecualikan tak hingga dan NaN?
Tipe bawaan number di Flow memungkinkan nilai-nilai "eksotis" seperti Infinity, -Infinity, dan NaN.
Bagaimana saya bisa menegakkan tipe agar hanya memperbolehkan bilangan nyata?
EDIT. Ini bukan pertanyaan tentang cara memeriksa apakah sebuah variabel adalah angka nyata. Ini tentang pengetikan dengan Flow.
Saya sedang mencari cara untuk menulis fungsi saya seperti:
// @flow
function sum (x: real, y: real) { ... }
Pertanyaan saya adalah bagaimana mendefinisikan tipe real sehingga dapat bekerja dengan Flow (http://flowtype.org/).
Jawaban #1
Anda tidak bisa melakukan itu menggunakan Flow. Anda akan membutuhkan pemeriksaan waktu jalan.
Lihat diskusi tentang masalah dengan bilangan real di sini: https://github.com/facebook/flow/issues/1406
Intinya, hampir semua operasi pada bilangan real bisa menghasilkan tak hingga, jadi membedakan antara bilangan real dan NaN/Tak hingga tidak akan terlalu berguna karena itu akan mengembalikan tipe yang tidak dijamin berupa bilangan real.
Sebagai contoh,
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
Terpisah dari diskusi itu, Flow tidak memiliki fasilitas untuk memasukkan dalam daftar hitam nilai-nilai tertentu sambil tetap mengizinkan nilai-nilai lain dari tipe yang sama. Anda hanya bisa memasukkan dalam daftar putih nilai-nilai, termasuk menggunakan union dan intersection.
Jawaban #2
Ada sedikit jalan tengah yang bisa Anda ambil dengan Flow. Ya, Anda akan perlu menggunakan pengecekan runtime untuk mewujudkannya pada akhirnya, tetapi Anda bisa membuat tipe opak yang akan membuat Flow menegakkan bahwa Anda tidak bisa melewati fungsi validasi tersebut. Pertama, dalam satu file, letakkan ini:
// @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;
}
Kemudian, Anda menggunakan itu seperti ini:
// @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!
