JavaScript Tips | 基本・共通ユーティリティ:基本判定・変換 – 整数変換

JavaScript JavaScript
スポンサーリンク

「整数変換」とは何をするものか

整数変換は、「文字列や小数など、いろいろな値を“業務で扱いやすい整数”にそろえる」ことです。
数量、個数、ページ番号、ID、在庫数、ポイント、金額(税抜き・税込みの端数処理)など、業務で「整数であってほしい値」は山ほどあります。

JavaScript は何でもかんでも number 型で扱うので、「これは整数として妥当か?」「小数が紛れ込んでいないか?」を自分でチェックしないといけません。
この「整数として扱ってよいかどうか」をきちんと判定しながら変換するのが、実務的な整数変換ユーティリティの役割です。


JavaScript の整数まわりの基本を押さえる

JavaScript の number 型は、整数と小数を区別しません。
ただし、「この値は整数か?」を判定するための Number.isInteger という関数があります。

console.log(Number.isInteger(10));     // true
console.log(Number.isInteger(10.5));   // false
console.log(Number.isInteger("10"));   // false
console.log(Number.isInteger(NaN));    // false
JavaScript

ここで重要なのは、「"10" は数値に見えるけれど、文字列のままでは整数ではない」ということです。
つまり、「文字列 → 数値に変換」「その数値が整数かどうかをチェック」という二段階で考える必要があります。


parseInt の特徴と注意点

整数変換と聞いて真っ先に思い浮かぶのが parseInt だと思います。
ただし、parseInt は「文字列の先頭から読めるところまで数値として読む」という性質があり、バリデーションとしては少し“ゆるい”です。

console.log(parseInt("10", 10));      // 10
console.log(parseInt("10px", 10));    // 10
console.log(parseInt("  20  ", 10));  // 20
console.log(parseInt("px10", 10));    // NaN
JavaScript

"10px" が 10 になってしまうのは、「単位付きの値から数値部分だけ取りたい」ときには便利ですが、「入力値として厳密にチェックしたい」ときには危険です。
また、基数(radix)を指定しないと "08" などで思わぬ挙動をする可能性があるため、実務では必ず第 2 引数に 10 を指定するのが定石です。


Number と Number.isInteger を組み合わせた“素直な”整数変換

業務で「厳しめの整数変換」をしたいなら、NumberNumber.isInteger を組み合わせるのが分かりやすくて安全です。

function toIntOrNaN(value) {
  const n = Number(value);
  return Number.isInteger(n) ? n : NaN;
}

console.log(toIntOrNaN("10"));     // 10
console.log(toIntOrNaN("10.5"));   // NaN
console.log(toIntOrNaN("abc"));    // NaN
console.log(toIntOrNaN(""));       // 0(ここは要件次第で変えたくなるポイント)
JavaScript

この書き方の良いところは、「まず数値として解釈できるか」「そのうえで整数かどうか」をはっきり分けていることです。
ただし、""null が 0 になってしまうなど、Number 特有の挙動がそのまま出るので、実務ではここに“自分たちのルール”を足していきます。


実務向けの toIntOrNull を設計する

業務でよくある要件は、「数値として解釈できないものは null にしたい」「空文字や空白だけは“未入力”として扱いたい」というものです。
それを反映した整数変換ユーティリティを作ってみます。

function toIntOrNull(value) {
  if (value === null || value === undefined) return null;
  if (typeof value === "string" && value.trim() === "") return null;

  const n = Number(value);
  if (!Number.isInteger(n)) return null;

  return n;
}

console.log(toIntOrNull("10"));      // 10
console.log(toIntOrNull("  10  "));  // 10
console.log(toIntOrNull("10.5"));    // null
console.log(toIntOrNull("abc"));     // null
console.log(toIntOrNull(""));        // null
console.log(toIntOrNull(null));      // null
JavaScript

ここで深掘りしたいポイントは三つあります。

一つ目は、「null / undefined / 空文字・空白だけの文字列は、そもそも変換対象外として null を返す」と決めていることです。
これにより、「未入力」と「不正な数値」を同じ扱い(null)にできます。

二つ目は、「Number で数値に変換したあと、必ず Number.isInteger で整数かどうかをチェックしている」ことです。
これにより、「10.5 のような小数が紛れ込んだら null にする」という厳しめのルールを実現できます。

三つ目は、「変換ロジックを一箇所に閉じ込めている」ことです。
プロジェクト全体で「整数変換は必ず toIntOrNull を通す」と決めておけば、あとから仕様を変えたくなっても、この関数だけ直せば済みます。


小数をどう扱うかを業務ルールとして決める

整数変換でよく迷うのが、「10.5 のような小数が来たときにどうするか」です。
選択肢としては、主に次のようなパターンがあります。

小数はエラー扱いにして null を返す(さきほどの toIntOrNull のようなパターン)。
小数は四捨五入して整数にする。
小数は切り捨て(floor)や切り上げ(ceil)で整数にする。

例えば、「金額は小数点以下を四捨五入して整数にする」という要件なら、次のように書けます。

function toRoundedIntOrNull(value) {
  if (value === null || value === undefined) return null;
  if (typeof value === "string" && value.trim() === "") return null;

  const n = Number(value);
  if (Number.isNaN(n)) return null;

  const rounded = Math.round(n);
  return rounded;
}

console.log(toRoundedIntOrNull("10.4"));  // 10
console.log(toRoundedIntOrNull("10.5"));  // 11
console.log(toRoundedIntOrNull("abc"));   // null
JavaScript

ここで大事なのは、「どのルールを採用するか」をなんとなくではなく“業務仕様として決める”ことです。
その仕様をユーティリティ関数に閉じ込めておけば、コードを読む人は「このプロジェクトでは小数はこう扱うんだな」とすぐに理解できます。


0 や負の値をどう扱うかも決めておく

整数変換では、「0 や負の値を許可するかどうか」も重要なポイントです。
例えば、「数量は 1 以上の整数だけ許可したい」という要件なら、変換後にさらにチェックを入れます。

function toPositiveIntOrNull(value) {
  const n = toIntOrNull(value);
  if (n === null) return null;
  if (n <= 0) return null;
  return n;
}

console.log(toPositiveIntOrNull("3"));   // 3
console.log(toPositiveIntOrNull("0"));   // null
console.log(toPositiveIntOrNull("-1"));  // null
console.log(toPositiveIntOrNull("abc")); // null
JavaScript

ここでは、「変換」と「業務ルールとしての範囲チェック」を分けているのがポイントです。
toIntOrNull は「整数として妥当かどうか」だけを見て、そのあとで「この業務では 1 以上だけ許可」といったルールを重ねています。


parseInt を使うなら“どこまで許すか”を意識する

parseInt も、使いどころを決めておけば十分実務で使えます。
例えば、「CSS の ’10px’ から数値部分だけ取りたい」「’001′ を 1 として扱いたい」といったケースです。

function parseCssPx(value) {
  if (typeof value !== "string") return null;
  const n = parseInt(value, 10);
  return Number.isNaN(n) ? null : n;
}

console.log(parseCssPx("10px"));   // 10
console.log(parseCssPx("px10"));   // null
console.log(parseCssPx("abc"));    // null
JavaScript

ここでも、「文字列の先頭に数値がある場合だけ許可する」「それ以外は null」というルールをはっきりさせています。
parseInt を“何でもありの変換”として使うのではなく、「この用途専用」として閉じ込めるのが安全です。


実務での具体的な利用イメージ

例えば、フォームから「数量」と「ページ番号」が文字列で送られてくるケースを考えます。

const raw = {
  quantity: "3",
  page: "0",
};

const quantity = toPositiveIntOrNull(raw.quantity);
const page = toIntOrNull(raw.page);

if (quantity === null) {
  console.log("数量が不正です(1 以上の整数を入力してください)");
} else {
  console.log("数量:", quantity);
}

const safePage = page === null || page < 1 ? 1 : page;
console.log("ページ番号:", safePage);
JavaScript

ここでは、「数量は 1 以上の整数だけ許可」「ページ番号は整数なら 0 や負の値も受け取るが、実際に使うときは 1 未満なら 1 に丸める」というように、
変換と業務ルールを段階的に適用しています。


小さな練習で感覚をつかむ

自分の手でユーティリティを書いてみると、一気に理解が深まります。
toIntOrNull, toRoundedIntOrNull, toPositiveIntOrNull を自分で実装して、次のような値を片っ端から試してみてください。

"10", " 10 ", "10.5", "0", "-1", "abc", "", " ", null, undefined, "001", "1e3" などを渡して、結果をコンソールに出してみると、「どこまでを許容するか」を自分の中で言語化できるようになります。

タイトルとURLをコピーしました