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 🙏

© 2024 – Pkg Stats / Ryan Hefner

zod-dev

v1.2.5

Published

Conditionally disables Zod run-time parsing in production while preserving type inference.

Downloads

71

Readme

🦞 Zod Dev

Conditionally disables Zod run-time parsing in production while preserving type inference.

⭐ If you find this tool useful please consider giving it a star on Github ⭐

Motivation

Primarily inspired by Yehonathan Sharvit's use of conditional validation with AJV as part of a data‑oriented programming approach.

Moreover, in Data-Oriented Programming, it is quite common to have some data validation parts enabled only during development and to disable them when the system runs in production.

Data-oriented Programming (2022)

There are several benefits to using Zod over AJV, the most prominent being the automatic inference of static types from schemas.

However, Zod is primarily designed for strict type safety, especially for use with TypeScript at the edges of your project's data ingress and egress. For this reason, Zod does not naturally lend itself well to pure JavaScript projects, usage of JSDoc and/or more loosely typed TypeScript projects by means of // @ts-check.

Basic Usage

npm install zod zod-dev

Simply wrap your Zod schema with the withDev functional mixin and provide a condition that determines whether run-time parsing should be enabled. For example, if you are using Vite, the following should suffice:

import { z } from 'zod';
import { withDev } from 'zod-dev'

const isDev = import.meta.env.MODE !== "production"

const schema = withDev(isDev, z.object({
    name: z.string(),
    email: z.string().email(),
    age: z.number().int().min(0),
}))

const value = {
    name: 'John Smith',
    email: '[email protected]',
    age: 24,
}

const result = schema.devParse(value)

image

Note that withDev leaves the original schema untouched, so you can still, for example, use person.parse(value) or person.shape.email should you wish.

Constructors

If you don't want to pass the condition manually each time you can use one of the following factory functions that implicitly include the condition. This means that you don't need to manually pass the condition each time you create a schema. Both serve the same purpose, and are simply a matter of preference.

The first, createWithDev create a custom withDev that automatically includes the condition:

import { z } from 'zod';
import { createWithDev } from 'zod-dev'

const isDev = import.meta.env.MODE !== "production"
const withDev = createWithDev(isDev)

const schema = withDev(isDev, z.object({
    name: z.string(),
    email: z.string().email(),
    age: z.number().int().min(0),
}))

const value = {
    name: 'John Smith',
    email: '[email protected]',
    age: 24,
}

const result = schema.devParse(value)

The second, createDevParse, creates devParse as a stand-alone function that accepts any value and schema. This provides a bit more flexibility since it is not bound to a specific schema:

import { z } from 'zod';
import { createDevParse } from 'zod-dev'

const isDev = import.meta.env.MODE !== "production"
const devParse = createDevParse(isDev)

const schema = z.object({
    name: z.string(),
    email: z.string().email(),
    age: z.number().int().min(0),
})

const value = {
    name: 'John Smith',
    email: '[email protected]',
    age: 24,
}

const result = devParse(value, schema)

CRUD Operations

Due to the ubiquity of immutable helper functions as a means to manipulate data in Data-oriente Programming, zod-dev also provides the means to create a basic CRUD helper functions as a means to manipulate objects that share the same schema in an array list.

This is done by making use of createArrayOperations which accepts a schema and returns an object as follows:

All helpers automatically run devParse on all inputs and outputs to ensure data integrity.

import { z } from "zod";
import { withDev, createArrayOperations } from "zod-dev";
const isDev = import.meta.env.MODE !== "production";

const schema = z.object({
    name: z.string(),
    email: z.string().email(),
    age: z.number().int().min(0),
})

export const { isCollection, getIndices, get, add, update, remove } = createArrayOperations(
  isDev,
  schema
);

let data = isCollection([
    {
        id: '4a932261-93dc-448a-91e5-bf3541510cfa',
        name: 'John Smith',
        email: '[email protected]',
        age: 24,
    },
    {
        id: '61627dac-2cb5-4934-a9bb-c2075e932ce8',
        name: 'Lorem Ipsum ',
        email: '[email protected]',
        age: 39,
    }
])

console.log(getIndices(data, '61627dac-2cb5-4934-a9bb-c2075e932ce8')) // [1]
console.log(getIndices(data, (item) => item.email.includes('@'))) // [0, 1]

// `get` works exactly like `getIndices` but returns the actual items instead
console.log(get(data, ['4a932261-93dc-448a-91e5-bf3541510cfa']))
console.log(get(data, (item) => item.email.includes('@')))

data = remove(data, '61627dac-2cb5-4934-a9bb-c2075e932ce8')
data = remove(data, (item) => item.name === 'John Smith')

// data is now `[]`

data = add(
    data, 
    {
        id: '61627dac-2cb5-4934-a9bb-c2075e932ce8',
        name: 'Lorem Ipsum ',
        email: '[email protected]',
        age: 39,
    }
)

data = add(
    data, 
    {
        id: '4a932261-93dc-448a-91e5-bf3541510cfa',
        name: 'John Smith',
        email: '[email protected]',
        age: 24,
    },
    'start'
)

// data is now same when created

data = update(data, (item) => ({ ...item, age: item.age + 1 })) 
// Ages are now `25` and `40`

data = update(data, (item) => ({ ...item, name: item.name.toReversed() }), '4a932261-93dc-448a-91e5-bf3541510cfa')
// `John Smith` name is now `htimS nhoJ`

Performance

Due to the nature of Zod's schema inference, it is several orders of magnitude slower than AJV for run-time parsing. This means that even when using Zod in a strict type-safety manner, there might still be performance benefits to disabling run-time validation in production environments.

As per Runtype Benchmarks:

image

If you're interested in the reason for the difference you can have a look at the follow conversation.

FAQ

What value should I use to toggle run-time checking?

This plugin was created for the use case of toggling run-time checking between different environments. However, since it merely accepts a boolean condition, parsing can effectively be toggled based on anything that can be expressed as true or false in JavaScript.

Should I use conditional run-time checking everywhere?

No. It is recommended that you still use .parse and/or .safeParse as intended when validating external consumed by you app. For example during form submissions or JSON data from an REST endpoint.