YupのSchemaオブジェクトで動的なバリデーションルールを設定する
例えば、最大値をユーザーごとに変えたいケースなど、APIから取得した値を使ってバリデーションしたいことがある。その際に、Schemaのあるファイルとデータを取得するファイルが同じなら、ただ変数を使えばいいのだけど、ファイルが別の場合の対応で悩んだ。
関数を使って渡す
YupのAPIに適した機能がないかを調べたが、Schemaオブジェクト自体はイミュータブルということでざっと見た感じなさそうだった。フォームの値自体をSchemaに渡すことはできるが、それ以外の値はわからん...というのをチームで相談した結果、Schemaオブジェクトをラップする関数を作って、引数をオブジェクトに渡す案が浮かんだ。こんな感じ。
export const getSchema = ( maxNum: number ): AnyObjectSchema => { // 適切な型がわからなかった... return yup.object({ point: yup .number() .max(maxNum, `${maxNum}より小さい数を入力してください`) }); };
TypeScriptを使ってるので、SchemaオブジェクトからFormDataの型を生成する。返り値のオブジェクトを使うのでReturnTypeを使った。
export type FormData = yup.Asserts< ReturnType<typeof getSchema> >;
react-hook-formを使ってるので、resolverで先ほどの関数を実行する。
const methods = useForm<FormData>({ resolver: yupResolver(getSchema(100)), });
初期値を設定しておいて、API実行後に値を置き換えたい場合は、引数側でgetSchema(data ?? 100)
などとするか、yupのschemaでdefault(0)
を使うと良い。