青いやつの進捗日記。

メモとしてべんきょうのしんちょくをかいていきます。あとで自分が検索しやすいもん

yupでnumberだけどnullも許す感じでバリデーションしたいとき

cpoint-lab.co.jp

React Hook Formとyupでフォームにバリデーションかけてます。

で、問題は、inputのtypeがnumberで、yupではnumber or nullでバリデーションかけたいとき。

yup.number()
yup.number().nullable()

だと、数字はいけますが、nullが入りません。

must be a `number` type, but the final value was: `NaN` (cast from the value `""`).

どうすればええにゃーってなっていたところ、

github.com

上記のissueで、下記のコメントが参考になりそうと教えてもらった。

https://github.com/jquense/yup/issues/298#issuecomment-678278303

これでいってみる

yup.string().matches(/^\d*$/, 'Wrong number')

バリデーションとしてのエラーは出なかった。が、consoleにエラーが。

Uncaught (in promise) {data: null, errors: Array(1)}
"Variable 'var' has an invalid value. Expected type 'Int' but was 'String'."

なるほどたしかに。GraphQL的にはIntなのですが、stringを入れようとしているのでエラー出た。だめそう。

うーどうしよう、と思ってたら1つ下に気になるコメントが

https://github.com/jquense/yup/issues/298#issuecomment-701305514

これを真似してみる

yup
.number()
.nullable()
.transform((value, originalValue) =>
  String(originalValue).trim() === '' ? null : value
)

これでいけたあああ!!!!nullも入るし数字も入る!!!!


このtransformとやらでなんか良い感じにしてくれているっぽい。これがないとエラー出てだめだったからな…でもちょっとこのtransformがなにしてるかちゃんとわかりきっていない。inputの値とってきてstring化してtrimとやらでとってきたものが空ならnull、あったら数字を値そのまま数字で返してる感じがする。

ちなみに結局整数で0以上で…みたいな条件も追加したので

yup
.number()
.typeError('数字を入力してください')
.integer('整数を入力してください')
.min(0, '0以上の数字を入れてください')
.nullable()
.transform((value, originalValue) =>
  String(originalValue).trim() === '' ? null : value
)

としました。