🛠️

[ React, TypeScript ] URL クエリパラメータ文字列が数字かどうかを判定する

2022/01/21に公開

動機

https://example.com?hoge=12345
のような URL を運用したいときに hoge の値が数字になっているかどうかを確かめたい

hoge の内容は react-router の query で取得でき、その型は string | string[] | undefined となっている。なので見た目は数字でも型は文字列ということだ

それから string[] と、配列になっている場合があるが、これは
?hoge=12345&hoge=67890 のように & で hoge をつなげると ["12345", "67890"] として取得できる

今回はこういった hoge の値に数字ではなく abc のような文字が含まれていないようにしたい
厳密には正規表現などで判定するべきなのだが簡単に対応したい

そういった要件をみたしつつやるとするならば以下のようにやる

isNaN もしくは isFinite を使う

見た目が数字の文字列が本当に数字かどうか判定するのに手軽な方法
こちらを参考
https://qiita.com/taku-0728/items/329e0bee1c49b7ce7cd1

isNaN は非数の場合に true を返し isFinite は数字 ( 有限数 ) の場合に true を返す。これらの真偽判定は大概真逆になっていると考えて差し支えない

本来ならより堅牢な Number.isNaNNumber.isFinite を使うべきなのだろうが TypeScript では isNaN や isFinite の引数に文字列を指定しようとすると number でないと怒られるのでどのみち isNaN(Number(hoge)) などとしてやる必要がある

考えられるクエリパラメータで真偽判定がどうなるかを検証。 isNaN で確かめてみる

isNaN(Number(hoge))
// 1 ...?hoge=12345 => false ( 数字である )
// 2 ...?hoge=12345abc => true ( 数字でない )
// 3 ...?hoge=12345&hoge=67890 => true ( 数字でない )
// 4 ...?hoge=12345abc&hoge=67890def => true ( 数字でない )

実際 Number(hoge) としている時点で hoge 数字以外の文字が含まれている場合この値は NaN になっているのでそういうものについては isNaN(NaN) を確かめていいるにすぎない

string[] となる場合 (3, 4) については厳密には配列かどうかの判定をしてそれぞれについて数字かどうかをチェックしなければいけないが今回は省略
3 や 4 を Number(hoge) すると NaN となるがどんな文字列が NaN となっているのかを確かめるために一度 String(hoge) としてみると

"12345,67890" // 3 の場合

となっていることがわかる。これを無理やり数値化しようとすると「 , 」 が入っているので NaN となる

補足

参考のリンクでも言及されているが nullfalsetrue は数値に変換すると 0 や 1 になるため isNaN をかますと false ( つまり数字ですよ〜 ) となる。これは正しい挙動だが今回の要件からするとそうなってほしくない
ただ状況がクエリパラメータなので null や false は文字列として入ってくる。 Number('null') は NaN になるので判定に影響はでないと考える

本当は 0x12 や小数や負数や BigInt やらも弾きたいのだがそうなってくると沼にはまりそうなので今回は abc のような文字が含まれていなければクリアということにしている

Discussion