Platform
    • Naming & Linter Rules
    • Styling Standards
    • Theme
    • Zod & Typing
    • Internationalization
Projects
  • API Connections & Tools
  1. Documentation
  2. Zod & Typing

Validation & Type Safety with Zod

Deterministic validation layer ensuring that all data entering the system conforms to the defined architectural contracts.

Zod Validation Architecture

Benefits: Zod allows combining runtime validation with TypeScript typing, creating a single source of truth for forms and API data.

Zod Schema & Types Structure

Naming Conventions

  • Zod Schemas:

    Located in schema/. Strictly one pair per operation: [name]-create.schema.ts ↔ [name]-create-form.types.ts. Runtime only — no z.infer exports here; ENUM_FORM_* is imported by the direct file path, not the ../types barrel.

  • Types & Interfaces:

    Located in types/[name]-[op]-form.types.ts. z.infer form types (e.g. TEntityCreateSchema) and ENUM_FORM_... live here, never in schema files. The schema is imported only via import type.

01Schema Definition

Creating a Zod object using i18nKey for localized error messages.

entities/entity-name/schema/entity-name-create.schema.ts
1import { z } from "zod"; 2import { type TEntityPageKeys, i18nKey } from "@/shared/config"; 3// прямой путь к form.types — не barrel "../types" (нет цикла schema ↔ types) 4import { ENUM_FORM_ENTITY_CREATE } from "../types/entity-name-create-form.types"; 5 6const msg = i18nKey<TEntityPageKeys>(); 7const F = ENUM_FORM_ENTITY_CREATE; 8 9/** Runtime only — never export inferred types from schema files. 10 * Одна схема на операцию: update — в entity-name-update.schema.ts */ 11export const ENTITY_CREATE_SCHEMA = z.object({ 12 [F.DESCRIPTION]: z 13 .string() 14 .trim() 15 .min(1, { 16 message: msg("form.overview.fields.description.errors.required") 17 }) 18 .min(3, { 19 message: msg("form.overview.fields.description.errors.min") 20 }) 21 .max(5000, { 22 message: msg("form.overview.fields.description.errors.max") 23 }), 24});

02Type Inference

Using z.infer to automatically generate TypeScript types from the schema.

entities/entity-name/types/entity-name-create-form.types.ts
1import type { FieldValues } from "react-hook-form"; 2import { z } from "zod"; 3// только import type — в рантайме зависимость schema → form.types односторонняя 4import type { ENTITY_CREATE_SCHEMA } from "../schema"; 5 6export const ENUM_FORM_ENTITY_CREATE = { 7 DESCRIPTION: "description", 8} as const; 9 10export type ENUM_FORM_ENTITY_CREATE_TYPE = 11 (typeof ENUM_FORM_ENTITY_CREATE)[keyof typeof ENUM_FORM_ENTITY_CREATE]; 12 13/** z.infer and form enums live in types/ — пара к entity-name-create.schema.ts */ 14export type TEntityCreateSchema = z.infer<typeof ENTITY_CREATE_SCHEMA> & 15 FieldValues;

03Form Integration

Connecting the schema to react-hook-form via zodResolver.

widgets/entity-name/ui/entity-name.tsx
1import { useForm } from "react-hook-form"; 2import { zodResolver } from "@hookform/resolvers/zod"; 3import { 4 type TEntityCreateSchema, 5 ENTITY_CREATE_SCHEMA, 6} from "@/entities/entity-name"; 7 8const form = useForm<TEntityCreateSchema>({ 9 resolver: zodResolver(ENTITY_CREATE_SCHEMA), 10 mode: "onSubmit" 11});