March 18, 2025

TS React Hook Form 推斷表單型別


[筆記] TS React Hook Form 推斷表單型別

對於主要表單操作型別整合做一個簡單的筆記

🌋 統一管理 表單驗證規則 以及相關型別內容

import React from "react";
import { type RegisterOptions, useForm } from "react-hook-form";

type FormValues = {
  username: string;
  email: string;
  isMarried: string;
};

type FormBaseTypes = {
  title?: string;
  type?: JSX.IntrinsicElements["input"]["type"];
};

const validationConfig: Record<
  keyof FormValues,
  FormBaseTypes & RegisterOptions<FormValues>
> = {
  username: {
    title: "用戶名",
    type: "text",
    required: "用戶名是必填的",
  },
  email: {
    title: "電子郵件",
    type: "email",
    required: "電子郵件是必填的",
    pattern: {
      value: /^[^@]+@[^@]+\.[^@]+$/,
      message: "無效的電子郵件格式",
    },
  },
  isMarried: {
    title: "是否已婚",
    type: "checkbox",
  },
};

const Page = () => {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<FormValues>();

  const onSubmit = (data: FormValues) => {
    console.log("表單資料:", data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      {Object.entries(validationConfig).map(([key, formField], idx) => {
        // 這裡暫時無法避免用 as, 因為無法直接推斷出 key 的型別
        const typedKey = key as keyof FormValues;
        return (
          <div key={idx}>
            <label>{formField.title}</label>
            <input
              type={formField.type}
              {...register(typedKey, validationConfig[typedKey])}
            />
            {errors[typedKey] ? <p>{errors[typedKey]?.message}</p> : null}
          </div>
        );
      })}

      <button type="submit">提交</button>
    </form>
  );
};

export default Page;