Neo Zero

is

Pool

Modern, comprehensive type checking library - TypeScript-first, tree-shakeable, zero dependencies

$ lpm install @lpm.dev/neo.is

@lpm.dev/neo.is

Modern, comprehensive type checking library for JavaScript - TypeScript-first, tree-shakeable, zero dependencies

Why neo.is?

Solves the micro-dependency crisis - Replaces 20+ fragmented type-checking packages (is-number, is-string, is-array, kind-of, etc.) with a single, comprehensive solution.

  • ๐ŸŽฏ Comprehensive: 30+ type checks in one package
  • ๐Ÿ“ฆ Tiny Bundle: 1.65 KB gzipped (45% under 3 KB target!)
  • ๐ŸŒฒ Tree-Shakeable: Import only what you need (~50-100 bytes per check)
  • ๐Ÿ”’ TypeScript Type Guards: Static type narrowing at compile-time
  • ๐ŸŒ Cross-Realm Safe: Works across iframes, workers, and realms
  • โšก Fast: Optimized performance for common checks
  • 0๏ธโƒฃ Zero Dependencies: No external runtime dependencies
  • โœ… 120+ Tests: Comprehensive test coverage

The Problem

The npm ecosystem has 100+ micro-dependencies for type checking:

  • is-number: 96M downloads/week
  • is-string: 28M downloads/week
  • is-plain-object: 42M downloads/week
  • ... and 97+ more

Total: 200M+ downloads/week of fragmented packages, each adding:

  • Security risk (any compromise affects millions)
  • Maintenance burden (each needs updates)
  • Bundle bloat (multiple similar implementations)

neo.is provides a comprehensive, modern alternative that can replace all of them.

Installation

lpm install @lpm.dev/neo.is

Quick Start

import { isNumber, isString, isArray, isPlainObject } from "@lpm.dev/neo.is";

// Numbers (TypeScript-aligned, NO string coercion by default)
isNumber(42); // true
isNumber("42"); // false (no coercion!)
isNumber(NaN); // false (NaN is not a number)
isNumber(Infinity); // false (Infinity is not finite)

// For string coercion (like is-number), use isNumeric
import { isNumeric } from "@lpm.dev/neo.is";
isNumeric("42"); // true (explicit coercion)
isNumeric("  42  "); // true (whitespace trimmed)

// Objects
isPlainObject({}); // true
isPlainObject(Object.create(null)); // true
isPlainObject([]); // false
isPlainObject(new Date()); // false

// Arrays
isArray([]); // true
isArray([1, 2, 3]); // true

// Strings
isString("hello"); // true
isString(""); // true

API Reference

Primitive Type Checks

import {
  isNumber, // Finite numbers (NOT NaN or Infinity)
  isString, // Strings
  isBoolean, // Booleans
  isSymbol, // Symbols
  isBigInt, // BigInts
  isNull, // Null
  isUndefined, // Undefined
  isNil, // Null OR Undefined
} from "@lpm.dev/neo.is";

// Examples
isNumber(42); // true
isString("test"); // true
isBoolean(true); // true
isSymbol(Symbol("x")); // true
isBigInt(42n); // true
isNull(null); // true
isUndefined(undefined); // true
isNil(null); // true
isNil(undefined); // true

Object Type Checks

import {
  isArray, // Arrays
  isObject, // Any object (including arrays)
  isPlainObject, // Plain objects only
  isDate, // Dates
  isRegExp, // Regular expressions
  isError, // Errors
  isMap, // Maps
  isSet, // Sets
  isWeakMap, // WeakMaps
  isWeakSet, // WeakSets
} from "@lpm.dev/neo.is";

// Examples
isArray([]); // true
isPlainObject({}); // true
isPlainObject(Object.create(null)); // true (null prototype)
isDate(new Date()); // true
isRegExp(/test/); // true
isError(new Error()); // true
isMap(new Map()); // true
isSet(new Set()); // true

Function Type Checks

import {
  isFunction, // Any function
  isAsyncFunction, // Async functions
  isGeneratorFunction, // Generator functions
  isGenerator, // Generator instances
  isPromise, // Promises
} from "@lpm.dev/neo.is";

// Examples
isFunction(() => {}); // true
isAsyncFunction(async () => {}); // true
isGeneratorFunction(function* () {}); // true
isPromise(Promise.resolve()); // true

Collection Checks

import {
  isEmpty, // Empty arrays, objects, strings, maps, sets
  isIterable, // Iterable objects
  isArrayLike, // Array-like objects (has .length)
} from "@lpm.dev/neo.is";

// Examples
isEmpty([]); // true
isEmpty({}); // true
isEmpty(""); // true
isEmpty(new Map()); // true
isEmpty([1]); // false

isIterable([]); // true
isIterable(new Set()); // true
isIterable({}); // false

isArrayLike([]); // true
isArrayLike("test"); // true (strings have .length)
isArrayLike({ length: 0 }); // true

Typed Array Checks

import {
  isTypedArray, // Any typed array
  isInt8Array, // Int8Array
  isUint8Array, // Uint8Array
  isUint8ClampedArray, // Uint8ClampedArray
  isInt16Array, // Int16Array
  isUint16Array, // Uint16Array
  isInt32Array, // Int32Array
  isUint32Array, // Uint32Array
  isFloat32Array, // Float32Array
  isFloat64Array, // Float64Array
  isBigInt64Array, // BigInt64Array
  isBigUint64Array, // BigUint64Array
} from "@lpm.dev/neo.is";

// Examples
isTypedArray(new Int8Array()); // true
isUint8Array(new Uint8Array()); // true
isFloat32Array(new Float32Array()); // true

Number Validators

import {
  isNumber, // Finite numbers
  isNaN, // NaN
  isFinite, // Finite numbers
  isInteger, // Integers
  isSafeInteger, // Safe integers
  isPositive, // Positive numbers (> 0)
  isNegative, // Negative numbers (< 0)
  isZero, // Zero (0 or -0)
  isNumeric, // Numeric values (with string coercion)
} from "@lpm.dev/neo.is";

// Examples
isNumber(42); // true
isNaN(NaN); // true
isFinite(42); // true
isInteger(42); // true
isSafeInteger(42); // true
isPositive(42); // true
isNegative(-42); // true
isZero(0); // true
isNumeric("42"); // true (string coercion!)

Utility Functions

import {
  getType, // Get type as string (like kind-of)
  createTypeGuard, // Create custom type guards
} from "@lpm.dev/neo.is";

// getType - Returns type string
getType(42); // 'number'
getType("hello"); // 'string'
getType([]); // 'array'
getType({}); // 'object'
getType(new Date()); // 'date'
getType(NaN); // 'nan'

// createTypeGuard - Create custom type guards
const isPositiveNumber = createTypeGuard<number>(
  (value): value is number => isNumber(value) && value > 0,
);

isPositiveNumber(42); // true
isPositiveNumber(-42); // false

Tree-Shaking

Import only what you need for optimal bundle size:

// Import single check (~50-100 bytes)
import { isNumber } from "@lpm.dev/neo.is";

// Import multiple (~150-300 bytes)
import { isNumber, isString, isArray } from "@lpm.dev/neo.is";

// Import by category
import { isNumber, isNaN, isFinite } from "@lpm.dev/neo.is/numbers";
import { isArray, isPlainObject } from "@lpm.dev/neo.is/objects";

// Import all (~1.65 KB gzipped)
import * as is from "@lpm.dev/neo.is";

TypeScript Type Guards

All type checks are TypeScript type guards that narrow types at compile-time:

function processValue(value: unknown) {
  if (isNumber(value)) {
    // TypeScript knows value is number here!
    console.log(value.toFixed(2));
  }

  if (isArray(value)) {
    // TypeScript knows value is array here!
    console.log(value.length);
  }

  if (isPlainObject(value)) {
    // TypeScript knows value is object here!
    console.log(Object.keys(value));
  }
}

Cross-Realm Safety

Works across iframes, workers, and different realms:

// iframe value fails instanceof check
const iframeArray = iframe.contentWindow.Array.of(1, 2, 3);
iframeArray instanceof Array; // false (different realm!)

// neo.is works correctly (uses Object.prototype.toString.call)
isArray(iframeArray); // true โœ“

Migration Guides

From is-number

// Before (is-number)
import isNumber from "is-number";

isNumber(42); // true
isNumber("42"); // true (string coercion!)
isNumber(NaN); // false
isNumber(Infinity); // false

// After (neo.is) - TypeScript-aligned
import { isNumber, isNumeric } from "@lpm.dev/neo.is";

isNumber(42); // true
isNumber("42"); // false (no coercion by default!)
isNumeric("42"); // true (explicit coercion)
isNumber(NaN); // false
isNumber(Infinity); // false

From kind-of

// Before (kind-of)
import kindOf from "kind-of";

const type = kindOf([]); // 'array'
// TypeScript doesn't know it's an array

// After (neo.is) - TypeScript type guards
import { isArray, getType } from "@lpm.dev/neo.is";

if (isArray(value)) {
  // TypeScript knows value is an array here!
  value.push(1);
}

// Or get type string like kind-of
const type = getType([]); // 'array'

Replacing Multiple Packages

// Before (multiple packages)
import isNumber from "is-number";
import isString from "is-string";
import isPlainObject from "is-plain-object";
import isArray from "isarray";
// ... 10+ more packages

// After (single package, tree-shaken)
import {
  isNumber,
  isString,
  isPlainObject,
  isArray,
  // ... import only what you need
} from "@lpm.dev/neo.is";

Real-World Use Cases

API Response Validation

import {
  isPlainObject,
  isNumber,
  isString,
  isArray,
  isDate,
} from "@lpm.dev/neo.is";

function validateUser(data: unknown) {
  if (!isPlainObject(data)) {
    throw new Error("Invalid user data");
  }

  if (!isNumber(data.id)) {
    throw new Error("Invalid user ID");
  }

  if (!isString(data.email)) {
    throw new Error("Invalid email");
  }

  if (!isArray(data.tags)) {
    throw new Error("Invalid tags");
  }

  if (!isDate(data.created)) {
    throw new Error("Invalid created date");
  }

  return data; // TypeScript knows the shape now
}

Form Input Validation

import { isNumeric, isString } from "@lpm.dev/neo.is";

function validateFormData(formData: Record<string, unknown>) {
  // Validate age is numeric (string from form)
  if (!isNumeric(formData.age)) {
    throw new Error("Age must be a number");
  }

  // Convert to number
  const age = Number(formData.age);

  // Validate email is string
  if (!isString(formData.email)) {
    throw new Error("Email must be a string");
  }

  return { age, email: formData.email };
}

Bundle Size Comparison

Package Bundle Size (gzipped) Tree-shakeable Type Guards
@lpm.dev/neo.is 1.65 KB โœ… Yes โœ… Yes
is-number 9.62 KB (package) โŒ No โŒ No
kind-of ~15 KB โŒ No โŒ No
Zod ~60 KB โŒ Limited โœ… Yes

Performance

Optimized for common use cases:

  • Primitive checks: 100M+ ops/sec (typeof baseline)
  • Object checks: 50M+ ops/sec (cross-realm toString)
  • Complex checks: 20M+ ops/sec (isPlainObject)

Browser Support

Works in all modern browsers and Node.js 18+:

  • Chrome, Firefox, Safari, Edge (latest 2 versions)
  • Node.js 18+
  • Deno, Bun
type-checkis-numberis-stringis-arraytypeoftype-guardtypescriptvalidationkind-ofcross-realm
Unlimited AccessInstall as many Pool packages as you need.
Fund Real WorkEvery install you run sends revenue directly to the developer who built it.

Taxes calculated at checkout based on your location.

Weekly Installs
3
Version
1.0.0
Published
LicenseMIT
Size207.81 KB
Files45
Node version>= 18
TypeScriptYes