Zod Utilz
Framework agnostic utilities for Zod
Table of contents
Purpose
- Simplify common tasks in Zod
- Fill the gap of features that might be missing in Zod
- Provide implementations for potential new features in Zod
Contribute
Always open to ideas. Positive or negative, all are welcome. Feel free to contribute an issue or PR.
Yet another library
You might not want to install yet another library only to get access to that one Util you need. No worries. Feel free to copy and paste the code you need into your project. It won't get updated when this library gets updated, but it will reduce your bundle size. :D
Perhaps in the future there will be a way to install only the Utilz you need. If you know how to do this, please let me know.
Installation
From npm (Node/Bun)
npm install zod_utilz
yarn add zod_utilz
pnpm add zod_utilz
bun add zod_utilz
Getting Started
import
Node/Bun
import { zu } from 'zod_utilz'
Deno
import { zu } from 'https://deno.land/x/zod_utilz/mod.ts'
// or
import { zu } from 'npm:zod_utilz'
Utilz
SPR
SPR stands for SafeParseResult
This enables optional chaining or nullish coalescing for z.SafeParseReturnType
.
import { zu } from 'zod_utilz'
const schema = z.object( { foo: z.string() } )
const result = zu.SPR( schema.safeParse( { foo: 42 } ) )
const fooDataOrErrors = result.data?.foo ?? result.error?.format().foo?._errors
makeErrorMap
Simplifies the process of making a ZodErrorMap
import { zu } from 'zod_utilz'
const errorMap = zu.makeErrorMap( {
required: 'Custom required message',
invalid_type: ( { data } ) => `${ data } is an invalid type`,
too_big: ( { maximum } ) => `Maximum length is ${ maximum }`,
invalid_enum_value: ( { data, options } ) =>
`${ data } is not a valid enum value. Valid options: ${ options?.join( ' | ' ) } `,
} )
const stringSchema = z.string( { errorMap } ).max( 32 )
zu.SPR( stringSchema.safeParse( undefined ) ).error?.issues[ 0 ].message
// Custom required message
zu.SPR( stringSchema.safeParse( 42 ) ).error?.issues[ 0 ].message
// 42 is an invalid type
zu.SPR( stringSchema.safeParse( 'this string is over the maximum length' ) ).error?.issues[ 0 ].message
// Maximum length is 32
const enumSchema = z.enum( [ 'foo', 'bar' ], { errorMap } )
zu.SPR( enumSchema.safeParse( 'baz' ) ).error?.issues[ 0 ].message
// baz is not a valid enum value. Valid options: foo | bar
useTypedParsers
Enables compile time type checking for zod parsers.
import { zu } from 'zod_utilz'
const schemaWithTypedParsers = zu.useTypedParsers( z.literal( 'foo' ) )
schemaWithTypedParsers.parse( 'foo' )
// no ts errors
schemaWithTypedParsers.parse( 'bar' )
// ^^^^^
// Argument of type '"bar"' is not assignable to parameter of type '"foo"'
coerce
Treats coercion errors like normal zod errors. Prevents throwing errors when using safeParse
.
import { zu } from 'zod_utilz'
const schema = zu.coerce( z.bigint() )
zu.SPR( schema.safeParse( '42' ) ).data
// 42n
zu.SPR( schema.safeParse( 'foo' ) ).error?.issues[ 0 ].message
// 'Expected bigint, received string'
useURLSearchParams
A way to parse URLSearchParams
import { zu } from 'zod_utilz'
const schema = zu.useURLSearchParams(
z.object( {
string: z.string(),
number: z.number(),
boolean: z.boolean(),
} )
)
zu.SPR( schema.safeParse(
new URLSearchParams( {
string: 'foo',
number: '42',
boolean: 'false',
} )
) ).data
// { string: 'foo', number: 42, boolean: false }
zu.SPR( schema.safeParse(
new URLSearchParams( {
string: '42',
number: 'false',
boolean: 'foo',
} )
) ).error?.format()
// {
// formErrors: [],
// fieldErrors: {
// string: [ 'Expected string, received number' ],
// number: [ 'Expected number, received boolean' ],
// boolean: [ 'Expected boolean, received string' ],
// }
// }
TODO
Always open to ideas. Positive or negative, all are welcome. Feel free to contribute an issue or PR.
- zu.coerce
- z.date()
- z.array()
- recursively coerce items
- z.string().array()
- z.number().array()
- z.object()
- recursively coerce props
- https://github.com/colinhacks/zod/discussions/1910
- FormData
- Partial Safe Parse
- BaseType (Recursively get the base type of a Zod type)
- zu.baseType( z.string() ) => z.string()
- zu.baseType( z.string().optional() ) => z.string()
- zu.baseType( z.string().optional().refine() ) => z.string()
- zu.baseType( z.string().array().optional().refine() ) => z.string().array()
- Make process for minifying
- Logo
- GitHub Actions
- Auto publish to npm