👏
Zodのrefineを使って""を弾くと、型定義からも""が除外された
react hook formを触っていると、『初期値に""を使いたいけど、バリデーション時には弾きたい』
と思い、refineを使用したがタイトルの問題が発生した。
🔧 問題
例えば、次のようなカテゴリー選択スキーマがあって
const schema = z.object({
category: z
.union([
z.enum(["A", "B", "C", "D"]),
z.literal(""),
])
.refine(val => val !== "", {
message: "カテゴリーを選択してください",
}),
});
このとき、得られる型が以下のようになった。
export type Schema = z.infer<typeof schema>
{
category: "A" | "B" | "C" | "D"
}
なんと、 "" が型から消えてしまった!
🤔 なぜ?
Zodはrefineを使って「常にバリデーションで失敗する値」がある場合、
その値は“ありえない”とみなして型定義から除外してしまうっぽい?
🙈 解決策
元の型を保持してasで明示した。
import { z } from "zod";
const rawCategory = z.union([
z.enum(["A", "B", "C", "D"]),
z.literal(""),
]);
const categorySchema = rawCategory.refine((val) => val !== "", {
message: "カテゴリーを選択してください",
}) as z.ZodType<z.infer<typeof rawCategory>>;
export const schema = z.object({
category: categorySchema,
});
export type Schema = z.infer<typeof schema>;
🎉 結果
"" が型に残り、バリデーション時に"" は弾けた!
export type Schema = z.infer<typeof schema>
{
category: "A" | "B" | "C" | "D" | ""
}
Discussion