- Published on
Why does Zod make all my schema fields optional?
- Authors
- Name
- Ripal & Zalak
Why does Zod make all my schema fields optional?
Zod is a versatile library for schema validation in TypeScript. However, developers often encounter an issue where Zod seems to make schema fields optional by default. Let’s explore why this happens and how you can ensure your fields are required.
Common Issue: Optional Fields
When validating user input, you may find that Zod treats fields as optional, leading to type conflicts. Consider the following schema:
import { z } from 'zod'
export const createUserSchema = z.object({
firstName: z.string({
required_error: 'First name is required',
}),
lastName: z
.string({
required_error: 'Last name is required',
})
.nonempty(),
password: z
.string({
required_error: 'Password is required',
})
.min(6, 'Password too short - should be 6 chars minimum'),
email: z
.string({
required_error: 'Email is required',
})
.email('Not a valid email')
.nonempty(),
})
When using the schema to validate input, you might encounter the following error:
Argument of type '{ firstName?: string; lastName?: string; email?: string; }' is not assignable to parameter of type 'CreateUserInput'.
Root Cause
This issue often stems from TypeScript compiler settings, specifically the strict
or strictNullChecks
options.
Solutions
strict
or strictNullChecks
1. Enable Ensure that your TypeScript configuration enforces strict null checks by adding or updating your tsconfig.json
:
{
"compilerOptions": {
"strict": true
}
}
Alternatively, if you need a less intrusive option, enable only strictNullChecks
:
{
"compilerOptions": {
"strictNullChecks": true
}
}
required_error
and min(1)
2. Use Zod provides the required_error
option to enforce required fields:
const userSchema = z.object({
firstName: z.string({
required_error: 'First name is required',
}),
lastName: z.string({
required_error: 'Last name is required',
}),
email: z
.string({
required_error: 'Email is required',
})
.email('Not a valid email'),
})
For non-empty string validation, use .min(1)
instead of the deprecated .nonempty()
:
const userSchema = z.object({
firstName: z
.string({
required_error: 'First name is required',
})
.min(1, 'First name cannot be empty'),
})
3. Combine Schemas for Refinements
If you need advanced validation, such as matching passwords, extend an existing schema:
const baseUserSchema = z.object({
firstName: z.string({
required_error: 'First name is required',
}),
password: z
.string({
required_error: 'Password is required',
})
.min(6, 'Password too short - should be 6 chars minimum'),
})
const extendedUserSchema = baseUserSchema
.extend({
passwordConfirmation: z.string({
required_error: 'Password confirmation is required',
}),
})
.refine((data) => data.password === data.passwordConfirmation, {
message: 'Passwords do not match',
path: ['passwordConfirmation'],
})
FAQ
Why does Zod treat fields as optional?
This usually occurs when strictNullChecks
is disabled in your TypeScript configuration. Zod relies on strict type checking to enforce required fields.
.nonempty()
in Zod?
What replaced Use .min(1)
for non-empty string validation. For example: z.string().min(1, 'Field cannot be empty')
.
strict
mode?
Can I use Zod without enabling Yes, but you must enable at least strictNullChecks
for reliable behavior.
How do I validate dependent fields in Zod?
Use the .refine()
method to enforce rules involving multiple fields, such as password matching.