如何将react-hook-form的handleSubmit与Zod Schema一起使用:将onSubmit数据输入为z.input而不是z.output

问题描述 投票:0回答:1

我正在使用带有 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 错误。

react-hook-form zod nextjs14
1个回答
0
投票

我通过传递更多泛型来解决这个问题。这是固定代码:

const {
  register,
  formState: { errors },
  handleSubmit,
} = useForm<
  z.input<typeof EmailOrPhoneSchema>,
  unknown,
  z.output<typeof EmailOrPhoneSchema>
>({
  resolver: zodResolver(EmailOrPhoneSchema),
});

此解决方案与此处讨论的问题相关:handleSubmit 不尊重 TypeScript #12050 中的 Zod 架构转换

© www.soinside.com 2019 - 2024. All rights reserved.