React Hook FormがZod v4に公式対応しました🎉
はじめに
先日 Zod バージョン 4(以下 v4)がリリースされましたね 🎉!
v4 ではパフォーマンス向上や、ライブラリのバンドルサイズの大幅削減、
そして軽量版の Zod Mini の登場など、開発者にとって嬉しいアップデートが多く含まれています。
(なお、これまでのバージョン 3 (v3) のサポートも継続されます。)
一方で Zod を利用している開発者の中には、React Hook Form との連携における v4 のサポート状況について気になっている方もいるかと思います。
公式の対応方法に関する情報もまだ少ないので、v4 と React Hook Form を連携させるための具体的な方法について共有します。
対応方法
v4 に対応するためには、@hookform/resolvers を v5.1.0 以降にアップデートすることで連携が可能です!
Zod 作者自らが出した修正 PR にわかりやすくまとめられているのですが、これまでの記述方法に変更を加えることなく、Zod v4、Zod Mini、そして従来の v3 パッケージのいずれでも利用できるよう対応がなされています。
コード例
Vite 公式の react-ts テンプレートで動作確認した例を載せておきます。
必要なライブラリはこれまでと同じです。
$ npm install react-hook-form @hookform/resolvers zod
import { useForm, type SubmitHandler } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod/v4";
const schema = z.object({
name: z.string().min(1),
age: z.number().min(0).max(150),
});
type Schema = z.infer<typeof schema>;
export default function Example() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm<Schema>({
resolver: zodResolver(schema),
defaultValues: {
name: "",
age: 0,
},
});
const onSubmit: SubmitHandler<Schema> = (data) => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("name")} />
{errors.name && <p>{errors.name.message}</p>}
<input {...register("age", { valueAsNumber: true })} type="number" />
{errors.age && <p>{errors.age.message}</p>}
<input type="submit" />
</form>
);
}
なお、Zod Mini を使用する場合、Zod の import と schema の書き方を以下に書き換える必要があります。
import { z } from "zod/v4-mini";
const schema = z.object({
name: z.string().check(z.minLength(1)),
age: z.number().check(z.minimum(1), z.maximum(150)),
});
standardSchemaResolver を使う手段について
standardSchemaResolver
を resolver に指定することで解決する方法も選択肢として共有されていました。[1]
しかし、この方法では useForm
の Generics 型が固定されてしまい、オリジナルの型をセットできないという欠点があります。(フォーム画面を作る上でここは結構痛い...)
そのため、一般的なフォーム開発では、前半でご紹介した対応方法を推奨します。
関連リンク
-
詳細は記事のリンク先で紹介されていますが、Zod v4 では
standardSchema
という標準化されたインターフェースが採用されています。standardSchemaResolver
はこのインターフェイス用の resolver になります。 ↩︎
Discussion