我正在使用带有 Zod 模式的 React-hook-form 来转换其输入。我遇到打字稿问题,其中
handleSubmit
函数将数据传递给我输入为 onSubmit
的 z.input<typeof EmailOrPhoneSchema>
函数,而不是预期的 z.output<typeof EmailOrPhoneSchema>
。
这是我的 Zod 架构:
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
属性的对象。但是,当我将此架构与react-hook-form一起使用时,onSubmit
函数接收输入为输入类型的数据,而不是输出类型。
如何确保react-hook-form正确地将传递给
onSubmit
的数据键入为z.output<typeof EmailOrPhoneSchema>
而不是z.input<typeof EmailOrPhoneSchema>
?
这是我的react-hook-form用法
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.log(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 不尊重 TypeScript #12050 中的 Zod 架构转换