is
PoolModern, comprehensive type checking library - TypeScript-first, tree-shakeable, zero dependencies
@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/weekis-string: 28M downloads/weekis-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.isQuick 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(""); // trueAPI 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); // trueObject 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()); // trueFunction 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()); // trueCollection 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 }); // trueTyped 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()); // trueNumber 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); // falseTree-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); // falseFrom 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
Taxes calculated at checkout based on your location.