Help us improve
Share bugs, ideas, or general feedback.
Creates reusable Zod v4 schemas to validate API payloads, forms, and config inputs in TypeScript apps. Handles coercion, transforms, errors, and type inference for runtime type safety.
npx claudepluginhub giuseppe-trisciuoglio/developer-kit --plugin developer-kit-typescriptHow this skill is triggered — by the user, by Claude, or both
Slash command
/developer-kit-typescript:zod-validation-utilitiesThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Production-ready Zod v4 patterns for reusable, type-safe validation with minimal boilerplate. Focuses on modern APIs, predictable error handling, and form integration.
Defines type-safe Zod schemas for forms, APIs, env vars; covers parsing, refinements, transformations, type inference, and integrations with React Hook Form, Next.js, tRPC.
Uses Zod schemas for runtime validation of APIs, forms, env vars, and external data while inferring TypeScript types as single source of truth.
Share bugs, ideas, or general feedback.
Production-ready Zod v4 patterns for reusable, type-safe validation with minimal boilerplate. Focuses on modern APIs, predictable error handling, and form integration.
zodResolvererror option for error messagesz.coerce.*) when input types are uncertainrefine/superRefine close to schema definitionsz.input/z.output) for consistencyWhen integrating validation into an API handler or service:
safeParse to handle errors gracefullyresult.success to branch on failure/successresult.data with full type inference in success pathSee example 7 (safeParse workflow) for the complete pattern.
import { z } from "zod";
export const UserIdSchema = z.uuid({ error: "Invalid user id" });
export const EmailSchema = z.email({ error: "Invalid email" });
export const WebsiteSchema = z.url({ error: "Invalid URL" });
export const UserProfileSchema = z.object(
{
id: UserIdSchema,
email: EmailSchema,
website: WebsiteSchema.optional(),
},
{ error: "Invalid user profile payload" }
);
import { z } from "zod";
export const PaginationQuerySchema = z.object({
page: z.coerce.number().int().min(1).default(1),
pageSize: z.coerce.number().int().min(1).max(100).default(20),
includeArchived: z.coerce.boolean().default(false),
});
export const DateFromUnknownSchema = z.preprocess(
(value) => (typeof value === "string" || value instanceof Date ? value : undefined),
z.coerce.date({ error: "Invalid date" })
);
export const NormalizedEmailSchema = z
.string()
.trim()
.toLowerCase()
.email({ error: "Invalid email" })
.transform((value) => value as Lowercase<string>);
import { z } from "zod";
const TagSchema = z.string().trim().min(1).max(40);
export const ProductSchema = z.object({
sku: z.string().min(3).max(24),
tags: z.array(TagSchema).max(15),
attributes: z.record(z.string(), z.union([z.string(), z.number(), z.boolean()])),
dimensions: z.tuple([z.number().positive(), z.number().positive(), z.number().positive()]),
});
export const PaymentMethodSchema = z.discriminatedUnion("type", [
z.object({ type: z.literal("card"), last4: z.string().regex(/^\d{4}$/) }),
z.object({ type: z.literal("paypal"), email: z.email() }),
z.object({ type: z.literal("wire"), iban: z.string().min(10) }),
]);
refine and superRefineimport { z } from "zod";
export const PasswordSchema = z
.string()
.min(12)
.refine((v) => /[A-Z]/.test(v), { error: "Must include an uppercase letter" })
.refine((v) => /\d/.test(v), { error: "Must include a number" });
export const RegisterSchema = z
.object({
email: z.email(),
password: PasswordSchema,
confirmPassword: z.string(),
})
.superRefine((data, ctx) => {
if (data.password !== data.confirmPassword) {
ctx.addIssue({
code: "custom",
path: ["confirmPassword"],
message: "Passwords do not match",
});
}
});
import { z } from "zod";
export const UserPreferencesSchema = z.object({
nickname: z.string().min(2).optional(), // undefined allowed
bio: z.string().max(280).nullable(), // null allowed
avatarUrl: z.url().nullish(), // null or undefined allowed
locale: z.string().default("en"), // fallback when missing
});
zodResolver)import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
const ProfileFormSchema = z.object({
name: z.string().min(2, { error: "Name too short" }),
email: z.email({ error: "Invalid email" }),
age: z.coerce.number().int().min(18),
});
type ProfileFormInput = z.input<typeof ProfileFormSchema>;
type ProfileFormOutput = z.output<typeof ProfileFormSchema>;
const form = useForm<ProfileFormInput, unknown, ProfileFormOutput>({
resolver: zodResolver(ProfileFormSchema),
criteriaMode: "all",
});
safeParseimport { z } from "zod";
import type { ZodError } from "zod";
const ResultSchema = z.object({ id: z.string(), name: z.string() });
function parseAndHandle(input: unknown) {
const result = ResultSchema.safeParse(input);
if (!result.success) {
const error = result.error as ZodError;
console.error("Validation failed:", error.errors);
return { success: false as const, error: error.format() };
}
return { success: true as const, data: result.data };
}
Tip: For advanced discriminated union patterns and complex React Hook Form workflows, see
references/advanced-patterns.md.
safeParse for recoverable flows; parse for fail-fast executionid, email, slug) to enforce consistencyz.input and z.output when transforms/coercions change runtime shapepreprocess; prefer explicit z.coerce.* where possiblezod major version (v4 APIs shown)error is the preferred option for custom errors in Zod v4 patterns