Array filtering May filter out items in array which does not match zod schema JSON.parse validation After JSON.parse() validation with zod we get truly typed data
const sortModelSchema = z.array(
z.object({
colId: z.string(),
sort: z.enum(['asc', 'desc']),
}),
)
const {
success: parseSortModelSuccess,
error: parseSortModelError,
data: parsedSortModel,
} = sortModelSchema.safeParse(JSON.parse(sortModel))
if (parseSortModelSuccess === false) {
throw new Error('Invalid sortModel format', parseSortModelError)
}
const sort = parsedSortModel.reduce<Record<string, 1 | -1>>(
(accumulator, item) => {
if (item.sort === 'asc') {
accumulator[item.colId] = 1
}
if (item.sort === 'desc') {
accumulator[item.colId] = -1
}
return accumulator
},
{},
)
Simple schema Here we validate data against the input data according to the schema
import { z } from 'zod'
const schema = z.object({
key: z.string(),
})
type InputValues = z.input<typeof schema> // { key: string }
type OutputValues = z.infer<typeof schema> // { key: string }
Schema with different input and output Data is validated against the schema inside the pipe() The output of the first schema becomes the input to the piped schema
const schema = z.object({
key: z.string().pipe(z.number()),
})
type InputValues = z.input<typeof schema> // { key: string }
type OutputValues = z.infer<typeof schema> // { key: number }
Transform transform() converts the parsed data AFTER validation into another form Validate if value is a number and then convert it into boolean
const schema = z.object({
key: z.string()
.pipe(z.number()).transform(val => Boolean(val)),
})
type InputValues = z.input<typeof schema> // { key: string }
type OutputValues = z.infer<typeof schema> // { key: boolean }
Preprocess preprocess() transforms the raw input data BEFORE validation Raw input could be anything Can be used for converting types before validation, sanitizing input, setting defaults Use when Input type is truly unknown/mixed Use when need to handle invalid input gracefully before validation "I don't care about input type, just make it work" Try to avoid if can
const schema = z.object({
key: z.preprocess(
(val) => String(val), // Convert anything to string first
z.string().min(3), // Then validate it's a string with min length 3
),
})
type InputValues = z.input<typeof schema> // { key?: unknown }
type OutputValues = z.infer<typeof schema> // { key: string }
Transform for pre-process Use when Input type is known and valid You want type safety on the input
const schema = z.object({
key: z.string() // Input type: string
.transform((val) => val.trim()) // Preprocess (trim)
.pipe(z.string().min(3)) // Validate trimmed result
.transform((val) => val.length) // Transforms to number
})
type InputValues = z.input<typeof schema> // { key: string }
type OutputValues = z.infer<typeof schema> // { key: number }
Default Commonly used for optional fields Only applies when the value is undefined Doesn't transform existing values Makes the input type optional May pass a function which will generate default
const schema = z.object({
key: z.string().default('tuna')
})
type InputValues = z.input<typeof schema> // { key?: string | undefined }
type OutputValues = z.infer<typeof schema> // { key: number }
const randomDefault = z.number().default(Math.random);
randomDefault.parse(undefined); // => 0.4413456736055323
randomDefault.parse(undefined); // => 0.1871840107401901
randomDefault.parse(undefined); // => 0.7223408162401552
Prefault Setting a default value will short-circuit the parsing process If the input is undefined, the default value is eagerly returned without validation Prefault value will is parsed
const schema = z.string().transform(val => val.length).default(0);
schema.parse(undefined); // => 0
z.string().transform(val => val.length).prefault("tuna");
schema.parse(undefined); // => 4
const a = z.string().trim().toUpperCase().prefault(" tuna ");
a.parse(undefined); // => "TUNA"
const b = z.string().trim().toUpperCase().default(" tuna ");
b.parse(undefined); // => " tuna "