JavaScript Tips | 基本・共通ユーティリティ:型チェック – 負の数判定

JavaScript JavaScript
スポンサーリンク

「負の数判定」とは何を見分けたいのか

負の数判定は、「その値が“0 より小さい数値として扱ってよいか”どうか」を見分けることです。
業務では、赤字金額、減算値、差分(マイナス方向)、残高の変化量など、「負の数を許可する」場面もあれば、「絶対に負の数はダメ」という場面もあります。

だからこそ、「これは負の数として扱ってよいか?」をきちんと判定できるユーティリティを持っておくと、
「本来マイナスになってはいけないところでマイナスが紛れ込む」「逆にマイナスを許すべきところで弾いてしまう」といった事故を防げます。


まずは「負の数」をきちんと定義する

負の数判定を実装する前に、「自分のプロジェクトでは何を“負の数”とみなすか」をはっきりさせる必要があります。

数学的には「0 より小さい数」が負の数です。
ここでポイントになるのは、次の二つです。

0 は負の数に含めない(< 0 か、<= -1 のようなイメージ)。
小数も負の数として扱うか(-1.5 などを許可するか)。

ここではまず、「0 より小さい数値(小数も含む)」を負の数とし、そのあとで「負の整数だけに絞る」パターンも触れます。


型が number の場合のシンプルな負の数判定

すでに「number 型である」ことが分かっている場合、負の数判定はとてもシンプルです。

function isNegativeNumber(value) {
  return typeof value === "number"
    && !Number.isNaN(value)
    && value < 0;
}

console.log(isNegativeNumber(-1));    // true
console.log(isNegativeNumber(-0.5));  // true
console.log(isNegativeNumber(0));     // false
console.log(isNegativeNumber(1));     // false
console.log(isNegativeNumber(NaN));   // false
console.log(isNegativeNumber("1"));   // false
JavaScript

ここで重要なポイントは三つあります。

一つ目は、「型が number かどうか」を必ずチェックしていることです。
文字列 " -1 " は見た目は負の数っぽいですが、この関数では false になります。「number 型専用」と割り切っているからです。

二つ目は、「NaN を除外している」ことです。
typeof NaN === "number" なので、そのままだと NaN も「負の数」と誤判定されてしまいます。!Number.isNaN(value) を入れることで、「壊れた数値」を弾いています。

三つ目は、「0 を含めない」と明示していることです。
value < 0 としているので、「-0」や「0」は負の数ではない扱いになります(-0 は JavaScript 的にはやや特殊ですが、通常は 0 と同じと考えて問題ありません)。


文字列も受け付ける「実務向けの負の数判定」

実務では、数値が文字列で渡ってくることが多いので、「number でも string でも受け付ける」ユーティリティがあると便利です。

function isNegativeNumeric(value) {
  if (typeof value === "number") {
    return !Number.isNaN(value) && value < 0;
  }

  if (typeof value === "string") {
    if (value.trim() === "") return false;

    const n = Number(value);
    return !Number.isNaN(n) && n < 0;
  }

  return false;
}

console.log(isNegativeNumeric(-1));       // true
console.log(isNegativeNumeric("-1"));     // true
console.log(isNegativeNumeric(" -1.5 ")); // true
console.log(isNegativeNumeric(0));        // false
console.log(isNegativeNumeric("0"));      // false
console.log(isNegativeNumeric("1"));      // false
console.log(isNegativeNumeric("abc"));    // false
console.log(isNegativeNumeric(""));       // false
console.log(isNegativeNumeric(null));     // false
JavaScript

ここで深掘りしたいポイントは次の通りです。

number の場合は、さきほどの isNegativeNumber と同じロジックで判定しています。
string の場合は、まず空文字や空白だけを弾き、そのうえで Number(value) で数値に変換し、NaN かどうかと 0 より小さいかどうかをチェックしています。
それ以外の型(null, undefined, オブジェクトなど)はすべて false にしています。「数値として扱えるのは number と string だけ」というルールを明示しています。

この isNegativeNumeric を使うと、「入力値が負の数として妥当かどうか」を一発で判定できるようになります。


「負の整数だけ」を許可したい場合

差分やステップ値など、「小数はダメで、-1, -2, -3 のような負の整数だけ許可したい」場面もあります。
その場合は、「整数かどうか」のチェックを追加します。

function isNegativeInteger(value) {
  if (typeof value === "number") {
    return Number.isInteger(value) && value < 0;
  }

  if (typeof value === "string") {
    if (value.trim() === "") return false;

    const n = Number(value);
    return Number.isInteger(n) && n < 0;
  }

  return false;
}

console.log(isNegativeInteger(-1));     // true
console.log(isNegativeInteger("-1"));   // true
console.log(isNegativeInteger(-1.5));   // false
console.log(isNegativeInteger("-1.5")); // false
console.log(isNegativeInteger(0));      // false
console.log(isNegativeInteger(1));      // false
JavaScript

ここでは Number.isInteger を使って、「整数かどうか」を判定しています。
「負の数」と「負の整数」は業務上の意味が違うので、ユーティリティも分けておくと読みやすくなります。


負の数判定と「業務ルール」の分け方

負の数判定は、「数値として妥当か」「0 より小さいか」を見ているだけです。
実務では、ここにさらに「どこまでマイナスを許すか」「特定の範囲だけ許可するか」といった業務ルールが乗ってきます。

例えば、「残高の変化量として -100〜100 の範囲だけ許可したい」という要件なら、次のように書けます。

function isValidDelta(value) {
  if (!isNegativeNumeric(value) && !isPositiveNumeric(value) && value !== 0) {
    return false;
  }

  const n = Number(value);
  return n >= -100 && n <= 100;
}
JavaScript

ここでは、「正の数判定」と組み合わせて、「正でも負でも 100 の範囲内なら OK」というルールを表現しています。
ポイントは、「負の数かどうか」と「業務上の範囲チェック」を分けて考えることです。


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

差分や増減値を扱う

例えば、「在庫の増減」を扱う関数を考えます。
正の数なら入庫、負の数なら出庫として扱いたいケースです。

function applyStockDelta(currentStock, delta) {
  if (!isNegativeNumeric(delta) && !isPositiveNumeric(delta) && delta !== 0) {
    throw new Error("増減値は数値で指定してください");
  }

  const n = Number(delta);
  const next = currentStock + n;

  if (next < 0) {
    throw new Error("在庫がマイナスになります");
  }

  return next;
}

console.log(applyStockDelta(10, "-3")); // 7
console.log(applyStockDelta(10, 5));    // 15
JavaScript

ここでは、「負の数を許可するが、結果として在庫がマイナスになるのは NG」という業務ルールを、
「負の数判定」と「結果のチェック」に分けて表現しています。

「負の数は絶対に禁止」のバリデーション

逆に、「この入力は絶対に負の数を許してはいけない」という場面もあります。
その場合は、「負の数なら即 NG」というシンプルなチェックを入れます。

function assertNonNegative(value) {
  if (isNegativeNumeric(value)) {
    throw new Error("負の値は指定できません");
  }
}

assertNonNegative("10");  // OK
assertNonNegative(0);     // OK
assertNonNegative("-1");  // ここで例外
JavaScript

このように、「負の数判定」を持っておくと、「負を許す場面」と「負を禁止する場面」の両方で、
意図をはっきり書けるようになります。


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

自分で isNegativeNumber, isNegativeNumeric, isNegativeInteger を実装して、次の値を片っ端から試してみてください。

-1, -1.5, 0, 1, " -1 ", "-1.5", "0", "1", "abc", "", " ", NaN, null, undefined

それぞれに対して、「どの関数が true になるか」「どこで false になるか」をコンソールに出してみると、
「数値判定」「NaN 判定」「正の数判定」「負の数判定」「整数判定」が頭の中でちゃんと整理されてきます。

ここまで整理できれば、あとは自分の業務ルールに合わせて、「どこまでマイナスを許すか」「小数を許すか」「範囲をどうするか」を足していくだけです。

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