is review
We installed is 3.3.2 as one dependency-free CommonJS package, then found a large collection of boolean predicates for primitives, arrays, objects, dates, functions, numeric relationships, encoded strings, Symbols, and BigInts. It is a compatibility-era utility, not a test runner or a schema validator: calls return true or false without paths or error messages, and the package has no TypeScript declarations. The current 3.3.2 release adds no API. Its changelog says it republishes clean 3.3.0 code after a hijacked account placed malware in 3.3.1 and 5.0.0, which npm subsequently deprecated.
is 3.3.2 installed in 0.6 seconds with 0 dependencies and a 1.8 KB gzipped browser bundle in our tests, but it supplies no TypeScript declarations and keeps several dated predicate definitions. Retain it for compatible legacy callers; new typed or schema-driven code has clearer choices.
We installed it
| Install | ✓ · 0.6s | 1 package on disk · 1 MB |
| Import | ✓ | ESM import works · require() works · CommonJS package |
| Browser | 1.8 KB | gzipped (5.6 KB minified), bundled with esbuild |
| Types | — | no TypeScript types found |
| Known vulns | 0 | 0 critical · 0 high · 0 moderate · 0 low (npm audit) |
Answers from our run
Does is install cleanly?
Yes. In a fresh container with an empty cache, npm install is finished in 0.6s, leaving 1 package and 1 MB on disk. npm audit reported no known vulnerabilities.
How much does is add to a browser bundle?
1.8 KB gzipped (5.6 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.
Does is work with both ESM and CommonJS?
Yes. Both import 'is' and require('is') worked in Node 22 in our run. The package is published as CommonJS.
Does is include TypeScript types?
No type declarations were found in our install, so TypeScript users need their own declarations.
is or @sindresorhus/is: which should you use?
@sindresorhus/is: Choose it for current TypeScript declarations, type guards, and assertion methods. is 3.3.2 installed in 0.6 seconds with 0 dependencies and a 1.8 KB gzipped browser bundle in our tests, but it supplies no TypeScript declarations and keeps several dated predicate definitions.
When should you not use is?
TypeScript narrowing is required. Version 3.3.2 ships no declaration file, so its methods are not typed predicates without declarations you maintain yourself.
Use it if
- You maintain CommonJS code that already depends on the package's exact definitions of empty, numeric, and object values.
- Old JavaScript engine compatibility matters, including boxed primitives and aliases retained for ES3 reserved-word concerns.
- A dependency-free set of boolean checks is enough and failures do not need field paths or explanations.
- You can wrap the few predicates you use behind names that spell out their less familiar edge cases.
- TypeScript narrowing is required. Version 3.3.2 ships no declaration file, so its methods are not typed predicates without declarations you maintain yourself.
- You expect `is.nan` to mirror `Number.isNaN`. The source returns true for any non-number, including strings, arrays, objects, and booleans.
- Your definition of empty excludes valid falsy data. Since version 3.0.0, `is.empty` deliberately accepts `0`, `false`, `NaN`, `null`, and `undefined`.
- You need sensible Infinity handling. In 3.3.2, both `is.even(Infinity)` and `is.odd(Infinity)` are true, and `is.within` returns true when any of its 3 inputs is infinite.
- Nested request validation needs coercion, issue paths, or messages. `is` checks individual values and its recursive equality function does not account for cycles, Map, Set, prototypes, or symbol keys.
Setup reality
Our fresh Node 22 Bookworm install of is 3.3.2 completed in 0.6 seconds. It left one package and 1 MB on disk; the package is 84 KB unpacked and declares 0 direct dependencies and 0 peer dependencies. npm audit found 0 known vulnerabilities. The engine range is Node 0.4 or newer. require() and ESM import both worked in our sandbox, although the published module is CommonJS and has no exports map.
There are no credentials, native addons, config files, or install scripts to prepare. TypeScript declarations are absent. A TS project therefore needs a locally maintained declaration, a third-party declaration you have checked against 3.3.2, or a different predicate package. The current release is specifically a clean republish of 3.3.0 after malicious 3.3.1 and 5.0.0 versions were deprecated; keep the resolved version pinned by your lockfile and do not copy those two version numbers from old examples.
The 5.6 KB minified browser bundle measured 1.8 KB gzipped, but some predicates assume their environment. is.element checks the global HTMLElement, so it returns false under plain Node. Deep equality descends through arrays and enumerable string-keyed object properties with no cycle guard. is.base64('') and is.hex('') both return true by design, which often calls for an explicit length check.
Numeric names need source-level attention. is.number accepts boxed Number objects, NaN, and infinities. is.integer rejects NaN and infinities but accepts boxed Number values after arithmetic coercion, so use Number.isInteger when native semantics are intended. Range helpers may throw TypeError for NaN or the wrong shape instead of returning false. These definitions are why this package fits compatibility work better than new validation code.
Patterns
Load the CommonJS export load-predicates
const is = require('is');
if (is.string(value)) {
console.log(value.toUpperCase());
}Version 3.3.2 publishes CommonJS with no exports map or TypeScript declaration file.
Tell null from undefined check-nullish-parts
if (is.nil(value)) {
console.log('null');
} else if (is.undef(value)) {
console.log('undefined');
}`is.nil` matches only null, while `is.undef` matches only undefined. `is.defined(null)` is true.
Check common built-in kinds check-native-kinds
const checks = {
array: is.array(value),
boolean: is.bool(value),
date: is.date(value),
error: is.error(value),
function: is.fn(value),
regexp: is.regexp(value),
};Several 3.3.2 checks use `Object.prototype.toString`, so boxed Boolean and String values also pass their matching predicates.
Accept an ordinary object literal check-object-literal
if (is.hash(value)) {
for (const key of Object.keys(value)) {
inspect(value[key]);
}
}`is.hash` requires `value.constructor === Object`. Class instances and objects created with a null prototype fail it.
Require a usable Date reject-invalid-date
if (!is.date.valid(value)) {
throw new TypeError('Expected a valid Date');
}`is.date(new Date('bad'))` is true because it checks the object kind. `is.date.valid` also checks the numeric date value.
Compose a finite numeric check check-finite-number
const isFiniteNumber = (value) =>
is.number(value) && !is.nan(value) && !is.infinite(value);`is.number` alone accepts NaN, both infinities, and boxed Number objects in version 3.3.2.
Use native integer semantics check-native-integer
if (Number.isInteger(value)) {
calculate(value);
}This deliberately uses the native method. `is.integer` accepts boxed numbers and does not express the same contract as `Number.isInteger`.
Limit emptiness to containers check-empty-collection
const isEmptyContainer =
(is.array(value) || is.string(value) || is.hash(value)) &&
is.empty(value);Since 3.0.0, `is.empty` also returns true for 0, false, NaN, null, and undefined, so the type gate changes the result set.
Compare acyclic arrays and objects compare-json-like-values
const same = is.equal(
{ page: 2, tags: ['ink', 'paper'] },
{ page: 2, tags: ['ink', 'paper'] },
);The recursive function handles arrays, dates, functions, and enumerable object properties. Cycles cause unbounded recursion, and Map or Set contents are not compared.
Reject empty encoded text check-nonempty-encoding
const validBase64 = is.string(value) && value.length > 0 && is.base64(value);
const validHex = is.string(value) && value.length > 0 && is.hex(value);Both encoding predicates return true for the empty string in 3.3.2, so the explicit length test is load-bearing.
Check a finite inclusive interval check-bounded-number
const values = [value, min, max];
const finite = values.every((item) =>
is.number(item) && !is.nan(item) && !is.infinite(item),
);
const accepted = finite && is.within(value, min, max);`is.within` is inclusive, throws for NaN or non-number inputs, and returns true if any of its 3 arguments is infinite.
Recognize Symbols and BigInts check-symbol-bigint
if (is.symbol(value)) console.log('symbol');
if (is.bigint(value)) console.log('bigint');BigInt detection arrived in the 3.3.0 code republished as 3.3.2. Both checks guard environments where the constructor is absent.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| @sindresorhus/is | npm | Choose it for current TypeScript declarations, type guards, and assertion methods. |
| is-what | npm | Choose it for a smaller typed set of checks aimed at present-day JavaScript values. |
| kind-of | npm | Choose it when one descriptive type string is clearer than a collection of predicates. |
| lodash | npm | Use focused methods such as `isEqual` or `isPlainObject` when Lodash is already in the project. |
More utils guides
lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

