utility-guards
Set of guard function for runtime type checking in JavaScript with complete TypeScript support
Motivation
JavaScript has a notoriously inconsistent system for runtime type checking — with scattered use of typeof
, instanceof
, Array.isArray
, Object.prototype.hasOwnProperty
, and more.
As well, TypeScript does not work properly with all of these checks, leading to confusion and bugs.
This library was created to unify all these scattered patterns into a consistent, type-safe, and minimal API.
Features
- 🧪 Simple runtime type checking
- 💡 Full TypeScript type inference support
- 📦 Tree-shaking friendly and zero dependencies
Installation
npm install utility-guards
Usage
import from the main package
import { isString, isNumber, isNil } from 'utility-guards';
isString(...);
isNumber(...);
isNil(...);
import from the sub-packages
import isString from 'utility-guards/isString';
import isNumber from 'utility-guards/isNumber';
import isNil from 'utility-guards/isNil';
isString(...);
isNumber(...);
isNil(...);
use is
default export container
import is from 'utility-guards';
is.String(...)
is.Number(...)
is.Nil(...)
Table of Contents
API
Primitive Checks
isString
isNumber
isFiniteNumber
isBoolean
isBigInt
isSymbol
isNull
isUndefined
isNil
isNaN
isPrimitive
isFalsy
Object Checks
Function & Class Checks
Special Structures
Advanced Structural Guards
Combinators
Utility
API
Primitive Checks
isString
Checks if a value is a string (based on typeof
)
isString('hello'); // true
isString(123); // false
isNumber
Checks if a value is a number (based on typeof
)
isNumber(123); // true
isNumber('123'); // false
isFiniteNumber
Checks if a values is a finite number (not NaN
, Infinity
, or -Infinity
)
isFiniteNumber(123); // true
isFiniteNumber(NaN); // false
isFiniteNumber(Infinity); // false
isFiniteNumber('42'); // false
isBoolean
Checks if a value is a boolean (based on typeof
)
isBoolean(true); // true
isBoolean(0); // false
isBigInt
Checks if value is a bigint
(based on typeof
)
isBigInt(123n); // true
isBigInt(BigInt(123)); // true
isBigInt(123); // false
isSymbol
Checks for symbol type (based on typeof
)
isSymbol(Symbol('foo')); // true
isNull
Checks if value is exactly null
.
isNull(null); // true
isNull(undefined); // false
isUndefined
Checks if value is exactly undefined
.
isUndefined(undefined); // true
isUndefined(null); // false
isNil
Checks if value is null
or undefined
.
isNil(null); // true
isNil(undefined); // true
isNaN
Strict NaN
check
isNaN(NaN); // true
isNaN('foo'); // false
isPrimitive
Checks for JS primitive types including (string
, number
, boolean
, bigint
, symbol
, null
, and undefined
).
isPrimitive('hello'); // true
isFalsy
Checks if value is falsy: false
, 0
, ''
, null
, undefined
isFalsy(false); // true
isFalsy(0); // true
isFalsy(''); // true
Object Checks
isAnyObject
Loose check for object-like values (including arrays, maps).
isAnyObject({}); // true
isAnyObject([]); // true
isAnyObject(new Map()); // true
isAnyObject(new MyClass()); // true
isPlainObject
Strictly checks for plain objects with default prototype.
isPlainObject({}); // true
isPlainObject(new Map()); // false
isPlainObject(new MyClass()); // false
isPlainObject(Object.create(null)); // true
isEmpty
Checks if the value is empty (e.g. empty array, string, object, map, set).
isEmpty({}); // true
isEmpty([]); // true
isEmpty(''); // true
isEmpty(new Map()); // true
isEmpty(new Set()); // true
isArray
Checks if value is an array (based on Array.isArray
)
isArray([]); // true
isArray({}); // false
isArrayOf
Checks if every item in an array passes a specified guard.
isArrayOf(['hello', 'world'], isString); // true
isArrayOf(['hello', 123], isString); // false
// can also use currying
is.ArrayOf(isString)(['hello', 'world']); // true
isTupleOf
Checks if the value is an array that exactly matches a given tuple schema.
isTupleOf(['hello', 123], [isString, isNumber]); // true
isTupleOf(['hello', 'world'], [isString, isNumber]); // false
isTupleOf([123], [isString, isNumber]); // false
isObjectOf
Checks if the value is an object that matches a given schema.
isObjectOf({ a: 1, b: 'hello' }, { a: isNumber, b: isString }); // true
isObjectOf({ a: 1, b: 'hello' }, { a: isNumber, b: isString, c: isBoolean }); // false
isObjectOf({ a: 1, b: 'hello', extra: true }, { a: isNumber, b: isString }); // true (see `isObjectExactOf` for strict check)
isObjectExactOf
Same as isObjectOf
, but strictly checks that the object matches the schema without extra keys.
isObjectExactOf({ a: 1, b: 'hello', extra: true }, { a: isNumber, b: isString }); // false
Function & Class Checks
isFunction
Checks if a value is a function (but not a ES6 class constructor).
isFunction(() => {}); // true
isFunction(function () {}); // true
isFunction(class MyClass {}); // false
Although technically es6 classes are functions as well, it's can not be called like a regular function and in most majority of cases this is not the expected behavior. So this guard is designed to check for regular functions only
isClass
Checks if value is a ES6 class constructor. Uses Object.prototype.toString
hack. Only works with ES6 classes defined with class
keyword.
isClass(class MyClass {}); // true
isClass(function () {}); // false
Special Structures
isRegExp
Checks if value is a RegExp
instance.
isRegExp(/abc/); // true
isRegExp(new RegExp('abc')); // true
isDate
Checks if value is a Date
instance.
isDate(new Date()); // true
isDate(new Date('INVALID')); // true, includes invalid dates (see `isValidDate` for strict check)
isDate('2023-01-01'); // false
isValidDate
Same as isDate
, but checks if the date is valid (i.e. not Invalid Date
).
isValidDate(new Date()); // true
isValidDate(new Date('INVALID')); // false
isIterable
Checks if value is iterable, meaning it has a [Symbol.iterator]
method and can be used in a for...of
loop and spread operator.
isIterable(new Set([1, 2])); // true
isIterable(new Map()); // true
isIterable(new Map().keys()); // true
isIterable((function* () {})()); // true
isIterable({}); // false
isPromise
Checks if value is a native Promise
instance.
isPromise(new Promise(() => {})); // true
isPromise({ then: () => {} }); // false
isPromiseLike
Checks if value is a promise-like object, meaning it has a then
method.
isPromiseLike(new Promise(() => {})); // true
isPromiseLike({ then: () => {} }); // true
isPromiseLike({ then: 'foo' }); // false
isError
Checks if value is an instance of Error
.
isError(new Error('foo')); // true
isError(new TypeError('foo')); // true
isError(new MyCustomError('foo')); // true
Advanced Structural Guards
isHasOwn
Checks if object has an own property (not inherited).
class Cls {
get key() {
return 'value';
}
}
const obj = { key: 'value' };
isHasOwn(obj, 'key'); // true
isHasOwn(new Cls(), 'key'); // false
isHasOwn('key')(obj); // support currying
isHasIn
Checks if property exists in object or its prototype chain.
isHasIn(obj, 'key'); // true
isHasIn(new Cls(), 'key'); // true
isHasIn('key')(obj); // support currying
isInstanceOf
Checks if value is instance of constructor using instanceof
.
class A {}
class B extends A {}
isInstanceOf(new A(), A); // true
isInstanceOf(new B(), A); // true
isInstanceExactOf
Strict check that prototype is exactly the one from constructor (not a subclass).
isInstanceExactOf(new A(), A); // true
isInstanceExactOf(new B(), A); // false
Combinators
$not
Inverts a given guard
const isNotString = $not(isString);
isNotString(123); // true
$some
Logical OR combinator: passes if any guard returns true.
const isStringOrNumber = $some(isString, isNumber);
isStringOrNumber('hello'); // true
isStringOrNumber(123); // true
$every
Logical AND combinator: passes if all guards return true.
const isStringAndNotEmpty = $every(isString, $not(isEmpty));
isStringAndNotEmpty('hello'); // true
isStringAndNotEmpty(''); // false
Utility
is
Checks two values for equality using Object.is
(or custom equality function).
Can be used for build more complex guards (e.g. isObjectOf
, isTupleOf
etc.).
is(123, 123); // true
is(123)(123); // support currying
isAny
A guard that always returns true
. Useful as a wildcard in validations.
isAny(ANYTHING); // true
Types
All guards follow this signature:
// basic guards with single argument
(value: unknown) => value is T
// guards with multiple arguments (isArrayOf, isTupleOf, isObjectOf, isInstanceOf, isHasOwn etc.)
// supports currying
(value: unknown, ...args: unknown[]) => value is T
(...args: unknown[]) => (value: unknown) => value is T
License
MIT © Resetand