0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Zodのcoerce機能で解決:React・React Hook Form・Zodを組み合わせて利用しているときの input type="number" が文字列になる問題の対処方法

Last updated at Posted at 2025-04-28

🤔 こんな問題に悩んでいませんか?

React・React Hook Form・Zodを組み合わせてフォームを作っていると、
<input type="number">の値が「数値」ではなく「文字列」として扱われてしまうことがあります。

たとえば

const value = formData.get('count'); // フォーム送信後の値
console.log(typeof value); // "string" 😱

見た目は数値用のフォーム要素なのに、
React側・サーバー側では結局 string として値を受け取ってしまい、
「数値として処理したいのに!」と困ることはありませんか?

📝 よくある解決パターン

こんな解決パターンを見かけることがあります。

// フォーム用とサーバー用、2つの型定義を作成
interface FormData {
  count: string;  // フォームからの入力は文字列
}

interface ProcessedData {
  count: number;  // 処理時は数値
}

このパターンだと、コードが冗長になり、型の不一致によるバグも発生しやすい問題があります。

✅ Zodのcoerce機能で解決!

Zodのcoerce.number()を使えば、この問題を解決できます。

import { z } from "zod";

// たった1つの型定義でOK! 🎉
const formSchema = z.object({
  count: z.coerce.number().int().min(1)
});

type FormData = z.infer<typeof formSchema>;

🚀 React Hook Formでの実装例

import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";

function CounterForm() {
  const { register, handleSubmit } = useForm<FormData>({
    resolver: zodResolver(formSchema)
  });

  const onSubmit = (data: FormData) => {
    console.log(typeof data.count); // "number" 🎯
    // 数値として直接計算できる!
    const doubled = data.count * 2;
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input type="number" {...register("count")} />
      <button type="submit">送信</button>
    </form>
  );
}

⚡ Next.jsのServer Actionsでも

'use server'

// Server Actionsでも同じスキーマが使える! 🔄
export async function saveCount(formData: FormData) {
  const data = formSchema.parse({
    count: formData.get('count')
  });
  
  // data.countは既に数値型 🧮
  // データベースに保存する処理...
}

💡 coerce.number()のポイント

  • 空文字列 → 0 に変換
  • 文字列 "123" → 数値 123 に変換
  • バリデーションも同時に設定可能(.int().min()など)

🌟 メリット

  • 型定義の一元化: フォーム用とサーバー用で別々の型が不要に
  • コードの簡素化: 変換処理を書く手間が省ける
  • 型安全性の向上: フォーム入力からサーバー処理まで一貫した型で扱える

🎯 まとめ

React・React Hook Form・Zodを組み合わせてフォームを使うと、
の値が文字列として扱われるケースがあります。

Zodの coerce.number() を使うことで、
型の管理をシンプルにしつつ、自然に数値として扱いやすくできました!

0
0
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?