🔢
react-hook-formとzodでnumber型を扱う時の個人的ベストプラクティス
結局フォームでは文字列で扱うのが安定
汎用的なメソッドを用意しておく
const NumberFromString = z
.string()
.regex(/^[+-]?\d*\.?\d+$/, { message: "数値を入力してください" })
.transform(Number);
const NumberFromZenkakuString = z
.string()
.transform(zenkkaku2hankaku)
.pipe(NumberFromString);
const validateTime = z
.number()
.int()
.min(0, { message: "0-23の数値を入力してください" })
.max(23, { message: "0-23の数値を入力してください" });
const validateMinute = z
.number()
.int()
.min(0, { message: "0-59の数値を入力してください" })
.max(59, { message: "0-59の数値を入力してください" });
全角入力を許すなら以下も追加
export const zenkkaku2hankaku = (str: string) => {
return str.replace(/[0-9]/g, (s) => {
return String.fromCharCode(s.charCodeAt(0) - 0xfee0);
});
};
usage
const scheduleSchema = z.object({
startTimeHour: NumberFromZenkakuString.pipe(validateTime),
startTimeMinute: NumberFromZenkakuString.pipe(validateMinute)
})
このスキーマを使ってreact-hook-formでフォームを作成すると、フォームの値の型はstringになる
APIなどに渡す前にキャストしてやること
const { getValue } = useForm<z.infer<typeof scheduleSchema>>()
const formInput = getValue()
const input = {
startTimeHour = parseInt(zenkaku2hankaku(formInput.startTimeHour))
}
キャスト面倒だけど仕方ない
type=numberやtype=dateはデフォルト値の設定が面倒だし、デザインが気に入らないケースもあるから使い勝手が悪いので当分使わない
参考リンク
Discussion