jet-validators ✈️

February 13, 2026 · View on GitHub

npm downloads types bundle size license

A comprehensive collection of TypeScript validator functions and utilities for common compile-time and runtime checks.

IDE snippet

jet-validators' parseObject function is "JIT-optimized" and one of the fastest schema validation tools available without requiring a compilation step. Check out these benchmarks here.

📚 Table of Contents

Looking for every exported function? Check out the full export reference.


***

👋 Introduction

jet-validators is a large collection of small, composable validator functions commonly used when validating values in TypeScript.

  • Drop-in validators you can import and use immediately
  • Covers the vast majority of real-world validation needs
  • Extremely fast and lightweight object schema validation
  • Tiny: bundle + zip size only 4.7kb
  • Zero dependencies

Quick Glance

import { isOptionalString } from 'jet-validators';

if (isOptionalString(value)) {
  // value is string | undefined
}


***

📦 Installation

npm install jet-validators


***

🔰 Basic Validators

Basic validators can be imported directly and used without configuration.

All validators follow consistent naming patterns:

  • isX
  • isOptionalX
  • isNullableX
  • isNullishX
  • isXArray (and variants)

Nullables

  • isUndef
  • isNull
  • isNullish (null | undefined)

isBoolean

  • isBoolean
  • isOptionalBoolean
  • isNullableBoolean
  • isNullishBoolean
  • isBooleanArray (+ variants)

isValidBoolean

Valid after running through parseBoolean

  • isValidBoolean
  • isOptionalValidBoolean
  • isNullableValidBoolean
  • isNullishValidBoolean
  • isValidBooleanArray (+ variants)

isNumber

  • isNumber (+ optional / nullable / array variants)

Sub-categories:

  • Positive
  • Negative
  • Unsigned

Each includes the full optional / nullable / array variants.


isInteger

Same structure as isNumber, including:

  • Positive
  • Negative
  • Unsigned

isBigInt

  • isBigInt
  • isOptionalBigInt
  • isNullableBigInt
  • isNullishBigInt
  • isBigIntArray (+ variants)

isValidNumber

Valid after numeric coercion.

  • isValidNumber
  • isOptionalValidNumber
  • isNullableValidNumber
  • isNullishValidNumber
  • isValidNumberArray (+ variants)

isString

  • isString (+ optional / nullable / array variants)

isNonEmptyString

Ensures .length > 0.

  • isNonEmptyString (+ variants)

isSymbol

  • isSymbol (+ variants)

isDate

Checks for a Date instance with a valid timestamp.

!isNaN(date.getTime());
  • isDate (+ variants)

isValidDate

Accepts Date, string, or number and validates via new Date(...).

  • isValidDate (+ variants)

isObject

Checks for a non-null object.

  • isObject (+ variants)

isFunction

  • isFunction (+ variants)


***

🧠 Complex Validators

These require an initialization step and return a validator function.

isValidString

  • isValidString (+ variants)
- Options

This takes an options object and returns a string validator.

optiontypedescription
minLengthnumberMinimum string length. Setting 0 allows '' (empty string) even if regex fails.
maxLengthnumberMaximum string length.
lengthnumberForces exact length (mutually exclusive with minLength/maxLength).
regexRegExpMust pass the given regular expression.
throwsbooleanThrow instead of returning false on validation failure.
errorMessage(value?: unknown, reason?: string) => stringCustomize the thrown error message when throws is true.
- Restrictions
constraintdetails
Exclusive lengthsProvide either the length field or the minLength/maxLength pair (never both).
Error customizationYou can supply errorMessage only when throws is true.
- Generics

You can supply a string generic if you want to narrow down the string type:

const typeValidator3 = isValidString<'foo'>({
  regex: /^foo$/,
  nullish: true,
});
// typeValidator3 => arg is 'foo' | null | undefined

Please see the test isValidString for a full example.


isInArray

const isAllowed = isInArray(['a', 'b', 'c']);
isAllowed('a'); // true

Supports optional / nullable variants.


isValidArray

Ensures every value in an array is contained in the validator array. Accepts optional minLength/maxLength arguments as well.

Note: This does not validate duplicates. It only checks that the argument is an array and every value present is allowed.

Please see the test isValidArray for a full example.

Supports optional / nullable variants.


isInRange

Checks whether a number (or numeric string) falls within a range.

Rules:

  • (min, max) → exclusive
  • [min], [max] → inclusive
  • [] → no bound
  • Reverse bounds → “outside range”
const between0and100 = isInRange([0], [100]);
between0and100(50); // true
between0and100('100'); // true
const negative = isInRange([], 0);
negative(-1); // true
const outside = isInRange(100, 50);
outside(101); // true
outside(75); // false



⚙️ Utilities

Utilities are imported from:

import { parseObject } from 'jet-validators/utils';

nonNullable

Removes null and undefined from a validator.

const isStrictString = nonNullable(isNullishString);

makeOptional / makeNullable / makeNullish

Wrap custom validators to extend their accepted types.

type Email = `${string}@${string}`;

const isEmail = (arg: unknown): arg is Email =>
  isString(arg) && EMAIL_REGEX.test(arg);

const isNullishEmail = makeNullish(isEmail); // --> "Email | null | undefined"

transform

Transforms a value before validation.

const isParsedArray = transform(JSON.parse, isNumberArray);
// isParsedArray is (arg: unknown, (transformedValue: number[]) => void): arg is number[]

Supports callbacks for accessing transformed values.


parseBoolean

Converts common boolean representations to actual booleans:

  • "true", "false" (case-insensitive)
  • "1", "0"
  • 1, 0
parseBoolean('TrUe'); // true
parseBoolean(0); // false

parseJson

Safely wraps JSON.parse.

const nums = parseJson<number[]>('[1,2,3]');

Throws if input is not a string.


***

📐 Object Schema Validation

Extremely fast and lightweight schema validation for objects using validator functions.


parseObject

  • If valid, returns a full deep clone of the provided object; otherwise returns false.
  • Removes unknown keys (by default)
  • Can enforce strict type-safety on schemas with generics
  • Can infer types from non-generic schemas.
  • Optional error callback
const parseUser = parseObject<IUser>({
  id: transform(Number, isNumber),
  name: isString,
});

OR

const parseUser = parseObject({
  id: transform(Number, isNumber),
  name: isString,
});

parseUser; // <-- Inferred type is: `(arg: unknown) => arg is { id: number; name: string }`

No need to call SomeUtilityType<typeof parseUser>

Supports:

  • optional / nullable
  • arrays
  • nested schemas
  • loose / strict modes

testObject

Same behavior as parseObject, but returns a type predicate.

if (testUser(user)) {
  // user is IUser
}

Combining parse + test

Nested schemas may use testObject inside parseObject. Supplying generics restores full type safety. Note that you cannot use parseObject on a nested schema because it returns the tested object, not a type predicate:

interface IUser {
  id: number;
  name: string;
  address: {
    street: string;
    city: string;
  };
  country?: {
    name: string;
    code: number;
  };
}

const parseUser = parseObject<IUser>({
  id: isUnsignedInteger,
  name: isString,

  // **testObject implied** address cannot be undefined
  // and type safety will allow extra keys. Safety is
  // inherited from root `parseUser` function
  address: {
    street: isString,
    city: isString,
  },

  // **testObject explicit** undefined allowed with the
  // optional option and strict type-safety is being
  // enforced
  country: testOptionalObject<IUser['country']>({
    abbreviation: isString,
    name: isString,
  }),
});

parse/testObject features and examples

Error handling

You can pass a callback as the second argument to the parseObject function, or as the second argument to the function returned from it, to receive an array of errors when any occur. Each error object has the format:

FieldTypeDescription
infostringGeneral information about the validation failure.
functionNamestringName of the validator function that failed.
valueunknownThe value that caused the validation failure (optional).
caughtstringError message caught from an unsafe validator function, if any.
keystringThe key at which the failure occurred but only when it happened at the root level.
keyPathstring[]Full path to the failing value for anything other than a key at the root level. If the failure occurs while inside an array variant (e.g. parseObjectArray), the first element represents the array index of the failing item.

Example

const parseUsersArray = parseObjectArray({ name: isString });
parseUsersArray([{ name: 'sean' }, { name: 123 }], (errors) => ...);

// Errors callback param above will be:
[{
  info: "Validator function returned false.",
  functionName: "isString",
  value: 123,
  keyPath: ["1", "name"]
}]

Wrapping parse/test

You may want to wrap parseObject to ensure all parse functions throw the same custom Error object. When wrapping these utilities, ensure your generics extend Schema<T> to preserve type safety.

Please see the section Wrapping with Custom Validators around schemas for a full example.


Adding Custom Validators to schemas

Any function of the form (arg: unknown) => arg is T can be used in schemas. If your custom validator checks an object and has nested errors, and you want those errors to bubble up to the highest level, you need to provide a callback. Otherwise, parseObject will only see the custom validator itself as the failing function, and nested errors will be ignored.

Please see the section Adding Custom Validators to schemas for a full example.


Manually creating error arrays

If you want to set up your own error array, you need to use the setIsParseErrorArray function to mark it as such because, in the real world, there could be validator functions with callbacks for reasons other than error handling.

Please see the section Manually creating error arrays for a full example.


Getting the type for a parse/testObject function

If you need the type for a parse function you created, use the utility type ReturnType with typeof <yourParseFunction> as its generic argument.

Please see the unit-test Test setting a type for the parseObject for a full example.


Testing multiple layers of Schema

Due to TypeScript limitations, you'll lose type safety when trying to wrap parseObject and pass a Schema down to another Schema. Wrap the nested schema with testObject and a generic.

Please see the unit-test Testing multiple layers of Schema for a full example.


Safety Modes

Control how extra object properties are handled. Nested schemas inherit the parent mode unless overridden:

  • loose – keep extra keys
  • default – remove extra keys (no error)
  • strict – remove extra keys and emit errors
const strictUser = strictParseObject({
  address: { street: isString }, // Will inherit strict from parent
  country: looseTestObject(...), // override parent mode for this nested schema
});


***

📄 License

MIT © seanpmaxwell1