Skip to content

Primitives

Six predicates for primitive-type and numeric checks. All are O(1) and run anywhere.

PredicateQuick rule
isString(v)typeof v === "string" (excludes new String(...))
isNumeric(v)Number-or-numeric-string, regex-based
isInt(v)typeof v === "number" AND Number.isInteger(v)
isFloat(v)typeof v === "number" AND finite AND stringifies to /^-?\d+\.\d+$/
isPrimitive(v)string | number | boolean | bigint (NOT symbol/null/undefined)
isScalar(v)string | number | boolean | bigint | symbol

isString

isString(""); // true
isString("hello"); // true
isString(`x${1}`); // true
isString(new String("x")); // false (wrapper objects are typeof "object")
isString(0); // false
isString(null); // false

isString is a value is string type predicate on unknown, so it narrows both branches:

import { isString } from "@mongez/supportive-is";
function upper(v: string | number) {
return isString(v) ? v.toUpperCase() : v.toFixed(2); // string / number
}

isPrimitive (value is string | boolean | number | bigint) and isScalar (value is string | boolean | number | symbol | bigint) are predicates too. isNumeric, isInt and isFloat return plain boolean on purpose: they accept a subset of number, so a predicate would make n never in the false branch for n: number (isNumeric also accepts numeric strings and [5]).

isNumeric

Recognizes numbers AND numeric strings:

isNumeric(0); // true
isNumeric(-1.5); // true
isNumeric("12"); // true
isNumeric("+1"); // true
isNumeric("1.5E-3"); // true
isNumeric(""); // false
isNumeric("1."); // false (trailing dot)
isNumeric("12abc"); // false
isNumeric(null); // false

isInt & isFloat

Both require typeof value === "number":

isInt(0); // true
isInt(1); // true
isInt(-1); // true
isInt(1.0); // true (`Number.isInteger(1.0)`)
isInt(1e21); // true (still an integer)
isInt(1.5); // false
isInt("2"); // false (data type matters)
isInt(NaN); // false
isInt(Infinity); // false
isFloat(1.5); // true
isFloat(0.1); // true
isFloat(-1.5); // true
isFloat(1); // false
isFloat(1.0); // false (no decimal in "1")
isFloat("1.5"); // false
isFloat(NaN); // false
isFloat(Infinity); // false

isPrimitive vs isScalar

The only difference is Symbol:

ValueisPrimitiveisScalar
"x"truetrue
1, 1.5, 1ntruetrue
true, falsetruetrue
Symbol("x")falsetrue
nullfalsefalse
undefinedfalsefalse
[], {}, () => {}falsefalse

isPrimitive is named for “what you can use in + / ===”, which excludes Symbol. isScalar is “anything that isn’t an object reference”.

Notes

  • isPrimitive(Symbol(...)) returning false is intentional — call isScalar instead if you want symbols included.
  • isInt now delegates to Number.isInteger, and isFloat gates on Number.isFinite, so both correctly handle signed values and reject NaN / Infinity.