npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

zod-valid

v2.0.5

Published

Lightweight utilities for flexible Zod schema validation (string, number, array, object, boolean, ISO).

Readme

A tiny helper library for Zod to safely normalize values to valid types with flexible handling of null, undefined, and fallback values. Supports strings, numbers, booleans, ISO dates, enums, arrays and objects.

It is very important to validate data coming from the server on the client side, making it more resilient to various errors, including critical ones.

Table of Contents

Features

  • Coerce any value to a valid type.
  • Fine-grained control over empty values (null / undefined):
    • none — disallow both.
    • optional — allow only undefined.
    • nullable — allow only null.
    • nullish — allow both.
  • Optionally replace empty values with a fallback.
  • Works with custom base schemas (z.string().min(3) etc.).
  • Includes helpers: toValidString, toValidNumber, toValidBoolean, toValidISO, toValidArray.

Installation

npm install zod-valid zod

Usage

toValidString

Creates a Zod schema that coerces any value to a string and provides flexible handling of empty values (null / undefined) and invalid inputs.

Usage forms:

  • toValidString(type, options?) — pass the base Zod schema as the first argument and options as the second.
  • toValidString(options) — pass only an options object, where options.type defines the base schema.

Behavior:

  • Converts any non-empty input to a string using String(val).
  • Allowed empty values (null / undefined) are controlled via allow and may be preserved or replaced with fallback.

Behavior options: | Option | Description | Default | Required | |-----------|---------------------------------------------------------------------------------------------------------------------|----------------|----------| | type | Base Zod schema to apply. | z.string() | No | | fallback| Value returned instead of invalid input or when replacing empty input (preserve: false). | null | No | | allow | Defines which empty values are considered valid:- "none" — neither null nor undefined allowed.- "optional" — only undefined allowed.- "nullable" — only null allowed.- "nullish" — both null and undefined allowed. | "nullish" | No | | preserve| Behavior for allowed empty values:- true — return them as-is.- false — replace with fallback. | true | No |

Examples:

import { toValidString } from "zod-valid";

const schema = toValidString();
schema.parse("abc");                  // "abc"
schema.parse(123);                    // "123"
schema.parse(null);                   // null (default allow="nullish", preserve=true)

const schema = toValidString({ allow: "optional" });
schema.parse(null);                   // "null" (null is coerced to string)
schema.parse(undefined);              // undefined

const schema = toValidString(z.string().min(2), { fallback: "N/A", preserve: false });
schema.parse("a");                    // "N/A"
schema.parse("abc");                  // "abc"
schema.parse(null);                   // "N/A"

const schema = toValidString({ type: z.email(), fallback: "empty" });
schema.parse("[email protected]"); // "[email protected]"
schema.parse("oops");                 // "empty"
schema.parse(null);                   // null
schema.parse(undefined);              // undefined

toValidNumber

Creates a Zod schema that coerces input values to numbers and provides flexible handling of empty values (null / undefined) and invalid inputs.

Usage forms:

  • toValidNumber(type, options?) — pass the base Zod schema as the first argument and options as the second.
  • toValidNumber(options) — pass only an options object, where options.type defines the base schema.

Behavior:

  • Converts values to numbers using Number(val).
  • Non-numeric or invalid values are replaced with fallback depending on allow and preserve.

Behavior options: | Option | Description | Default | Required | |-----------|---------------------------------------------------------------------------------------------------------------------|----------------|----------| | type | Base Zod schema to apply. | z.number() | No | | fallback| Value returned instead of invalid input or when replacing empty input (preserve: false). | null | No | | allow | Defines which empty values are considered valid:- "none" — neither null nor undefined allowed.- "optional" — only undefined allowed.- "nullable" — only null allowed.- "nullish" — both null and undefined allowed. | "nullish" | No | | preserve| Behavior for allowed empty values:- true — return them as-is.- false — replace with fallback. | true | No |

Examples:

import { toValidNumber } from "zod-valid";

const schema = toValidNumber();
schema.parse(42);        // 42
schema.parse("123");     // 123
schema.parse(null);      // null (default allow="nullish", preserve=true)

const schema = toValidNumber({ allow: "optional" });
schema.parse(null);      // null replaced with "null" logic → returns fallback if preserve=false
schema.parse(undefined); // undefined

const schemaTyped = toValidNumber(z.number().min(10), { fallback: 0 });
schemaTyped.parse(5);    // 0 (invalid, replaced with fallback)
schemaTyped.parse(20);   // 20

const schema = toValidNumber({ allow: "nullish", fallback: 99, preserve: false });
schema.parse("abc");     // 99 (invalid string → fallback)
schema.parse(null);      // 99
schema.parse(undefined); // 99

toValidISO

Creates a Zod schema that coerces input to ISO 8601 date strings and provides flexible handling of empty values (null / undefined) and invalid inputs.

Usage forms:

  • toValidISO(type, options?) — pass the base Zod schema as the first argument and options as the second.
  • toValidISO(options) — pass only an options object, where options.type defines the base schema.

Behavior:

  • Converts valid string inputs to ISO 8601 dates.
  • Non-string or invalid values are replaced with fallback depending on allow and preserve.

Behavior options: | Option | Description | Default | Required | |-----------|---------------------------------------------------------------------------------------------------------------------|--------------------|----------| | type | Base Zod schema to apply. | z.iso.datetime() | No | | fallback| Value returned instead of invalid input or when replacing empty input (preserve: false). | null | No | | allow | Defines which empty values are considered valid:- "none" — neither null nor undefined allowed.- "optional" — only undefined allowed.- "nullable" — only null allowed.- "nullish" — both null and undefined allowed. | "nullish" | No | | preserve| Behavior for allowed empty values:- true — return them as-is.- false — replace with fallback. | true | No |

Examples:

import { toValidISO } from "zod-valid";

const schema = toValidISO();
schema.parse("2025-09-02 10:00"); // "2025-09-02T10:00:00Z"
schema.parse(null);               // null (default allow="nullish", preserve=true)

const schema = toValidISO({ allow: "optional" });
schema.parse(null);               // null (default fallback)
schema.parse(undefined);          // undefined

const schemaTyped = toValidISO(z.string().datetime(), { fallback: "1970-01-01T00:00:00Z" });
schemaTyped.parse("invalid");     // "1970-01-01T00:00:00Z"
schemaTyped.parse("2025-09-11");  // "2025-09-11T00:00:00.000Z"

const schema = toValidISO({ allow: "nullable", fallback: "N/A", preserve: false });
schemaFallback.parse("abc");      // "N/A"
schemaFallback.parse(null);       // "N/A"
schemaFallback.parse(undefined);  // "N/A"

toValidBoolean

Creates a Zod schema that coerces input to boolean values and provides flexible handling of empty values (null / undefined) and invalid inputs.

Usage forms:

  • toValidBoolean(type, options?) — pass the base Zod schema as the first argument and options as the second.
  • toValidBoolean(options) — pass only an options object, where options.type defines the base schema.

Behavior:

  • Converts values to boolean ("true"/"false", numbers, objects).
  • Allowed empty values (null / undefined) are controlled via allow and may be preserved or replaced.
  • Other invalid values are coerced to boolean following the above rules.

Behavior options: | Option | Description | Default | Required | |-----------|---------------------------------------------------------------------------------------------------------------------|----------------|----------| | type | Base Zod schema to apply. | z.boolean() | No | | fallback| Value returned instead of invalid input or when replacing empty input (preserve: false). | null | No | | allow | Defines which empty values are considered valid:- "none" — neither null nor undefined allowed.- "optional" — only undefined allowed.- "nullable" — only null allowed.- "nullish" — both null and undefined allowed. | "nullish" | No | | preserve| Behavior for allowed empty values:- true — return them as-is.- false — replace with fallback. | true | No |

Examples:

import { toValidBoolean } from "zod-valid";

const schema = toValidBoolean();
schema.parse("true");            // true
schema.parse("FALSE");           // false
schema.parse(1);                 // true
schema.parse(0);                 // false
schema.parse(null);              // null (default allow="nullish", preserve=true)

const schema = toValidBoolean({ allow: "optional" });
schema.parse(null);              // false
schema.parse(undefined);         // undefined

const schemaTyped = toValidBoolean(z.boolean(), { fallback: false });
schemaTyped.parse("true");       // true
schemaTyped.parse("oops");       // false

const schemaFallback = toValidBoolean({ allow: "nullish", fallback: false, preserve: false });
schemaFallback.parse(null);      // false
schemaFallback.parse(undefined); // false
schemaFallback.parse("oops");    // false

toValidArray

Creates a Zod schema that ensures input is an array of elements matching type, with flexible handling of empty (null/undefined) and invalid values.

Usage forms:

  • toValidArray(type, options?) — pass the base Zod schema as the first argument and options as the second.
  • toValidArray(options) — pass only an options object, where options.type defines the base schema.

Behavior:

  • If input is not an array or is an invalid value, it is replaced with fallback (depending on allow and preserve).
  • Allowed empty values (null / undefined) are controlled via allow and may be preserved or replaced.
  • If strict: true, removes any elements that do not pass the type schema (invalid elements), as well as null and undefined, but does not remove fallback values if they are not null or undefined.

Behavior options: | Option | Description | Default | Required | |-----------|-----------------------------------------------------------------------------------------------------------|------------------|----------| | type | Zod schema for array elements. Can be passed either as the first argument (toValidArray(z.string())) or inside the options object (toValidArray({ type: z.string() })). | z.array(z.never()) | No | | fallback| Value returned instead of invalid input or when replacing empty input (preserve: false). | [] | No | | allow | Defines which empty values are considered valid:- "none" — neither null nor undefined allowed.- "optional" — only undefined allowed.- "nullable" — only null allowed.- "nullish" — both null and undefined allowed. | "nullish" | No | | preserve| Behavior for allowed empty values:- true — return them as-is.- false — replace with fallback. | true | No | | strict | Whether to strictly enforce the element schema:- true — removes any elements that do not pass the type schema (invalid elements).Also removes null and undefined values, even if allowed by allow.Does not remove fallback values if they are not null or undefined.- false — invalid elements and allowed empty values are preserved (or replaced by fallback if preserve: false). | true | No |

Examples:

import { toValidArray } from "zod-valid";

const schema = toValidArray(z.string());
schema.parse(["a", "b"]);              // ["a", "b"]
schema.parse(null);                    // null (allow="nullish", preserve=true)

const schemaTyped = toValidArray(z.number(), { allow: "optional" });
schemaTyped.parse([1, 2]);             // [1, 2]
schemaTyped.parse(undefined);          // undefined

const schema3 = toValidArray({ type: z.number(), allow: "nullable", fallback: [], preserve: false });
schema3.parse("oops");                 // []
schema3.parse(null);                   // []

const strictSchema = toValidArray({ type: z.number(), strict: true });
strictSchema.parse([1, "x", 2, null]); // [1, 2] — removes invalid values, null, and undefined; preserves fallback values

toValidObject

Creates a Zod schema that ensures the input is a plain object (validated by type), with flexible handling of empty values (null / undefined) and a fallback value for invalid cases.

Usage forms:

  • toValidObject(type, options?) — pass the base Zod schema as the first argument and options as the second.
  • toValidObject(options) — pass only an options object, where options.type defines the base schema.

Behavior:

  • If the input is a plain object ({}), it is validated against type.
  • Non-object or invalid values are replaced with fallback depending on allow and preserve.

Behavior options: | Option | Description | Default | Required | |-----------|----------------------------------------------------------------------------------------------|----------------------------------------|----------| | type | Base Zod schema for validating objects. | z.object({}).catchall(z.any()) (any plain object) | No | | fallback| Value returned instead of invalid input or when replacing empty input (preserve: false). | null | No | | allow | Defines which empty values are considered valid:- "none" — neither null nor undefined allowed.- "optional" — only undefined allowed.- "nullable" — only null allowed.- "nullish" — both null and undefined allowed. | "nullish" | No | | preserve| Behavior for allowed empty values:- true — return them as-is.- false — replace with fallback. | true | No |

Examples:

import { toValidArray } from "zod-valid";

const schemaNum = toValidObject({ type: z.object({ x: z.number() }) });
schemaNum.parse({ x: 42 });        // { x: 42 }
schemaNum.parse({ x: "oops" });    // null (invalid, replaced with fallback)

const schemaStrict = toValidObject(z.object({ id: z.string() }), { allow: "nullish" });
schemaStrict.parse({ id: "abc" }); // { id: "abc" }
schemaStrict.parse({ id: 123 });   // null (invalid, fallback applied)

const RoleEnum = z.enum(["admin", "user", "guest"]);
const schemaEnum = toValidObject({ type: RoleEnum, allow: "optional" });
schemaEnum.parse("admin");         // "admin"
schemaEnum.parse("superuser");     // null (invalid value -> fallback)
schemaEnum.parse(null);            // null (replaced with fallback, since null not allowed)
schemaEnum.parse(undefined);       // undefined

const schemaReplace = toValidObject({ type: z.object({}), allow: "nullish", fallback: {}, preserve: false });
schemaReplace.parse(null);         // {} (null allowed, but replaced with fallback)
schemaReplace.parse(undefined);    // {} (undefined allowed, but replaced with fallback)
schemaReplace.parse("oops");       // {} (invalid, replaced with fallback)

Utils

nonNullable

You can remove null and undefined from the result of an API call using the nonNullable utility. This utility adds a z.transform to the schema, removing null and undefined from the type and returning a custom error.

Behavior options: | Option | Description | Default | Required | |----------|------------------|--------------------------------|----------| | schema | A Zod schema | — | Yes | | message| Error message text | "Cannot be null or undefined" | No |

Examples:

import z from "zod";
import { toValidString, toValidNumber } from "zod-valid";
import { nonNullable } from "zod-valid/utils";

const emailSchema = z.object({
  id: toValidNumber({ allow: "none", preserve: false }),
  name: toValidString(),
  surname: toValidString(),
  address: toValidString(),
});

/*
  {
    id: number;v
    name?: string | null | undefined;
    surname?: string | null | undefined;
    address?: string | null | undefined;
  }
*/
type Email = z.infer<typeof emailSchema>;

const formSchema = z.object({
  name: nonNullable(emailSchema.shape.name).refine((v) => v, "Name is required"),
  surname: emailSchema.shape.name.nonoptional(),
  address: nonNullable(emailSchema.shape.name).optional(),
});

/*
  {
    name: string;
    surname: string | null;
    address?: string | undefined;
  }
*/
type Form = z.infer<typeof formSchema>;

Examples

ℹ️ You can find all possible usage examples for each function in the tests folder.

import { z } from "zod";
import {
  toValidNumber,
  toValidString,
  toValidISO,
  toValidArray,
  toValidBoolean,
  toValidObject,
} from "zod-valid";

const ResponseSchema = toValidObject({
  type: z.object({
    users: toValidArray({
      type: toValidObject({
        type: z.object({
          id: toValidNumber({ allow: "none" }),
          name: toValidString(),
          email: toValidString({ type: z.email(), fallback: "N/A", preserve: false }),
          isActive: toValidBoolean(),
          createdAt: toValidISO(),
        }),
      }),
      preserve: false,
    })
  }),
});

// or more shorter

const ResponseSchema = toValidObject(z.object({
  users: toValidArray(
    toValidObject(z.object({
      id: toValidNumber({ allow: "none" }),
      name: toValidString(),
      email: toValidString(z.email(), { fallback: "N/A", preserve: false }),
      isActive: toValidBoolean(),
      createdAt: toValidISO(),
    })),
    {
      preserve: false,
    },
  )
}));

/*
  type ResponseType = {
    users: {
      id: number;
      name?: string | null | undefined;
      email: string;
      isActive?: boolean | null | undefined;
      createdAt?: string | null | undefined;
    }[]
  } | null | undefined
*/
type ResponseType = z.infer<typeof ResponseSchema>

async function getUser() {
  const response = await fetch("/api/users");
  const rawData = await response.json();
  const validData = ResponseSchema.parse(rawData);
  return validData;
}

License

MIT © 2025 Nikerin Evgenii [email protected] (https://github.com/4nikerin)