Let’s make it super clear with a real example.
You have this:
type ShippingFormInputs = {
email: string;
age: number;
};
and this Zod schema:
const shippingFormSchema = z.object({
email: z.string().email(),
age: z.number().min(18),
});
and this form:
const { register, handleSubmit, formState: { errors } } =
useForm<ShippingFormInputs>({
resolver: zodResolver(shippingFormSchema)
});
🧠 What happens step by step
1. TypeScript (<ShippingFormInputs>) — BEFORE running code
This only works while coding.
Example mistake:
register("emial"); // ❌ typo
👉 TypeScript will immediately show error:
"Property 'emial' does not exist"
✔ This is ONLY for developer safety.
2. Zod (shippingFormSchema) — WHEN user submits form
Now user runs the app and enters:
email: "abc"
age: 10
Then user clicks submit.
👉 Now Zod runs:
z.string().email() ❌ invalid
z.number().min(18) ❌ invalid
So Zod returns:
errors = {
email: "Invalid email",
age: "Must be at least 18"
}
✔ This is REAL runtime validation.
⚡ Key idea (VERY IMPORTANT)
| Tool | When it works | What it checks |
|---|---|---|
TypeScript <ShippingFormInputs> | Before running code | Developer mistakes (typos, wrong fields) |
Zod (resolver) | When user submits form | Real input values |
🧪 Simple mental model
TypeScript = Guard for YOU (developer)
"Are you writing correct code?"
Zod = Guard for USER input
"Did user enter valid data?"
🔥 Final flow
User submits form:
1. User clicks submit
2. Zod runs first (validates real data)
3. If OK → form submits
4. If not → errors shown
Meanwhile TypeScript already helped you while writing code.
Comments
Post a Comment