Кастомный хук для работы с формой

Область применения: Проекты на React, где в десятке компонентов повторяется одна и та же логика работы с формами: состояние полей, валидация, touched, ошибки, сабмит. Вместо копирования удобно вынести всё в переиспользуемый хук.

Ожидаемый результат: Полноценный кастомный хук useForm с типизацией на TypeScript, поддержкой валидации, состояний touched/dirty, обработки ошибок и сабмита — без внешних зависимостей, по духу похож на react-hook-form, но под ваш проект.

Кастомный useForm хук
Ты — senior React-разработчик. Напиши переиспользуемый хук useForm на TypeScript для управления формами в моём проекте. Требуемая функциональность: 1. Значения полей через generic-типизацию: `useForm`. 2. Инициализация через initialValues. 3. Схема валидации как функция `(values) => errors` — без привязки к Yup/Zod, но с возможностью их подключить. 4. Состояния для каждого поля: value, error, touched, dirty. 5. Хелперы: register(fieldName), setValue, setError, reset, handleSubmit. 6. Валидация на blur и на сабмите, а не на каждом нажатии клавиши. 7. Обработка асинхронного сабмита: состояние isSubmitting, корректная блокировка кнопки. 8. Возможность серверных ошибок: если бэк вернул ошибки по полям — подсветить их. Что вернуть: — Код хука с исчерпывающими типами. — Пример использования в компоненте: форма логина с email и паролем. — Короткое объяснение, почему выбран useReducer, а не несколько useState (или наоборот). — Список того, что НЕ делает этот хук, и когда стоит взять react-hook-form вместо него. — 3 юнит-теста на Vitest: успешный сабмит, валидация на blur, обработка серверной ошибки. Не усложняй. Хук не должен превращаться в недоделанный react-hook-form.

Хорошие кастомные хуки рождаются из паттернов, которые вы уже трижды скопипастили. Если формы в проекте простые — свой useForm легче поддерживать, чем внешнюю библиотеку. Но как только появляются вложенные поля, динамические массивы и сложная валидация — честнее взять готовое решение.