Я использую форму реагирования со схемой Zod, которая преобразует вводимые данные. Я столкнулся с проблемой машинописного текста, когда функция handleSubmit
передает данные в мою функцию onSubmit
, набранную как z.input<typeof EmailOrPhoneSchema>
вместо ожидаемого z.output<typeof EmailOrPhoneSchema>
.
Вот моя схема Зода:
import { z } from "zod";
const phoneRegex = /^\+?[1-9]\d{1,14}$/;
const EmailOrPhoneSchema = z.object({
emailOrPhone: z
.string()
.trim()
.refine(
(value) => {
const isEmail = z.string().email().safeParse(value).success;
const isPhone = phoneRegex.test(value);
return isEmail || isPhone;
},
{
message: "Invalid email or phone number",
}
),
})
.transform(({ emailOrPhone }) => {
const isEmail = z.string().email().safeParse(emailOrPhone).success;
const isPhone = phoneRegex.test(emailOrPhone);
return {
isEmail,
isPhone,
value: isEmail ? emailOrPhone.toLowerCase() : emailOrPhone.replace(/\D/g, ""),
};
});
export default EmailOrPhoneSchema;
Схема принимает на вход строку, но выводит объект со свойствами isEmail
, isPhone
и value
. Однако когда я использую эту схему с формой реагирования, функция onSubmit
получает данные, типизированные как тип ввода, а не как тип вывода.
Как я могу гарантировать, что форма реагирования правильно вводит данные, передаваемые в onSubmit
, как z.output<typeof EmailOrPhoneSchema>
вместо z.input<typeof EmailOrPhoneSchema>
?
вот мое использование формы реагирования
import React from "react";
import { Label } from "../ui/label";
import { Input } from "../ui/input";
import SubmitButton from "../small/submit-button";
import { useForm } from "react-hook-form";
import { z } from "zod";
import EmailOrPhoneSchema from "@/schemas/shared/email-or-phone";
import { zodResolver } from "@hookform/resolvers/zod";
type Props = {};
export default function ForgotPasswordForm({}: Props) {
const {
register,
formState: { errors },
handleSubmit,
} = useForm<z.input<typeof EmailOrPhoneSchema>>({
resolver: zodResolver(EmailOrPhoneSchema),
});
function onSubmit(data: z.output<typeof EmailOrPhoneSchema>) {
console.info(data);
}
return (
<form onSubmit = {handleSubmit(onSubmit)}>
<div className = "space-y-2">
<Label htmlFor = "email-phone">Email or Phone</Label>
<Input
{...register("emailOrPhone")}
id = "email-phone"
type = "text"
placeholder = "Enter your email or phone number"
required
/>
{errors.emailOrPhone && (
<span className = "text-red-500 text-xs">
{errors.emailOrPhone.message}
</span>
)}
</div>
<SubmitButton type = "submit" className = "w-full mt-4">
Reset Password
</SubmitButton>
</form>
);
}
Я попытался записать выходные данные в свою функцию onSubmit
, и фактическая структура данных соответствует тому, что я ожидаю от преобразованной схемы. Однако типизация TypeScript не отражает это преобразование.
В частности, я ожидал, что данные в onSubmit
будут введены как:
{
isEmail: boolean;
isPhone: boolean;
value: string;
}
Но вместо этого TypeScript определяет тип как:
{
emailOrPhone: string;
}
Это несоответствие между фактической структурой данных и типом TypeScript вызывает проблемы в моем коде, когда я пытаюсь получить доступ к преобразованным свойствам. Сами данные верны, но я получаю ошибки TypeScript при попытке использовать их по назначению.
Я исправил это, передав больше дженериков. Вот фиксированный код:
const {
register,
formState: { errors },
handleSubmit,
} = useForm<
z.input<typeof EmailOrPhoneSchema>,
unknown,
z.output<typeof EmailOrPhoneSchema>
>({
resolver: zodResolver(EmailOrPhoneSchema),
});
Это решение связано с проблемой, обсуждаемой здесь: handleSubmit не учитывает преобразования схемы Zod в TypeScript #12050