2021年3月1日
プログラミング
Reactで使えるバリデーションライブラリを紹介!
はじめに
フォームの実装のライブラリはFormik、React Hook Form、React Final Formのどれにしよう…と悩むことは多いと思うのですが、バリデーションを何で行おうというのは考える機会が少ないと思います。
というのも、React Hook FormもFormikもYupを推しているので、あまり調査せずにYupを使う方が多いのではないでしょうか。そもそもReact Hook FormはデフォルトではHTML標準のバリデーション機能を使用しているので、バリデーションライブラリを意識したことないという方もいるかもしれません。
実は非常に多くのバリデーションライブラリがあるので、今回は色々紹介して比較していきます!
バリデーションライブラリの種類
ざっと挙げるだけでもこれくらいあります。
・Joi
・Yup
・zod
・io-ts
・Superstruct
・Vest
まだまだたくさんあるのですが、今回紹介するのはこの6つとさせていただきます。
npm trendsは以下の通りです。(スクショは2021年3月1日時点)
joi vs superstruct vs yup vs io-ts vs zod vs vest
各ライブラリの紹介
Joi
・作成日:2012年9月
・ファイルサイズ:42.4KB
今回紹介する中で作成日が一番早く、今でも圧倒的人気があります。
Node.jsで使うのがメインですが、joi-browserというブラウザ用のものもあります。
長所
・date().greater(日付)
やstring().hostname()
など、様々なAPIが用意されています。
・エラーメッセージをカスタマイズできます。
短所
・ファイルサイズが大きい
・~~TypeScriptに対応していない~~ 2020年に対応されましたが、後に紹介するYupやzodと異なり、スキーマから型を自動生成することは出来ないので自分で書く必要がある
・unionやintersectionのような複雑なことができない
Yup
・作成日:2014年1月
・ファイルサイズ:18.1KB
Joiに影響されて作成されました。Joiと違うところは、主な使用用途をクライアントサイドに絞り、よりシンプルにしました(一応、Nodeでも使えます)。また、parseとvalidationを別のステップに切り分けることで、状況に応じて両方行ったり片方だけ行ったりすることができるようにしました。
長所
・(Joiよりは少ないが、)様々なAPIが用意されている
短所
・unionやintersectionのような複雑なことはできない
zod
・作成日:2020年3月
・ファイルサイズ:9.3KB
TypeScript-firstなライブラリです。重複する型宣言を可能な限り排除することを目標にしています。
Blitz.jsでも使われています!
長所
・メソッドチェーンを使うことで、ネストしたオブジェクトをよりシンプルに書けるようにしている
・ファイルサイズが小さい
短所
・APIの種類が少なめ
io-ts
・作成日:2017年1月
・ファイルサイズ:5.2KB
TypeScript用にゼロから設計されたライブラリです。fp-ts の作者が作りました。
長所
・型を厳密につけることができる
短所
・プログラミングの純粋さを優先しているのでフォームに組み込むのが難しい
・TypeScriptで関数型プログラミングをするライブラリのfp-tsをベースにしているのでこちらの知識が必要になる。
Superstruct
・作成日:2017年11月
・ファイルサイズ:3.2KB
TypeScript, Flow, Go, GraphQLに影響されて作ったので、それらを触ったことがある人なら容易に理解できるようなAPIになっています。
runtimeにバリデーションすることで詳細なエラーを出しています。
長所
・ファイルサイズが小さい
・エラーが詳細
短所
・pick、omit、mergeなどのobjectメソッドが不足している
・配列で「最低でも1要素は必要」という制限をつけることができない
Vest
・作成日:2019年11月
・ファイルサイズ:6.5KB
MochaやJestのようなJSユニットテストツールに構文を寄せています。フレームワークに依存しないように作られていて、Reactなどのフレームワークがなくても動作します。
長所
・フレームワークに依存しない
・test.only()
やtest.skip()
でテストするフィールドを決定することができる
・テストの書き方に慣れ親しんでいる人にとってはとても書きやすい
短所
・スキーマから型を自動生成することは出来ない
zodとYupを細かく比較してみよう
・TypeScriptに対応
・使い勝手が良さそう
という視点で、zodとYupに絞ってみました。2つを細かく比較してみます。
比較項目
- 型生成
- 複雑なスキーマ定義
- 便利なAPIの種類
型生成:Yup△ zod◎
zodもYupも、schemaから型を生成することができます。ですが、Yupではいくつか型生成が上手く行かないことがあります。
オブジェクトのoptionalな値がrequiredになってしまう
zodもYupも、schemaから型を生成することができます。ですが、Yupではいくつか型生成が上手く行かないことがあります。
オブジェクトのoptionalな値がrequiredになってしまう
yup
Yupの場合、オブジェクトのoptionalな値も型生成するとrequiredになってしまうという不具合があります。
schema↓
const schema = yup.object({
asdf: yup.string(), // yupはデフォルトでoptional
});
schema.validate({}); // 成功する
型生成↓
type SchemaType = yup.InferType<typeof schema>;
// 生成された型 { asdf: string }
// 本当は { asdf?: string } になってほしい
zod
schema↓
const schema = zod.object({
asdf: zod.string().optional(), // zodはデフォルトでrequired
});
schema.parse({}); // 成功する
型生成↓
type SchemaType = zod.infer<typeof schema>;
// { asdf?: string | undefined }
「配列の要素を最低1つはほしい」という型が上手くいかない
yup
「配列の要素を最低1つはほしい」というschemaを作ったとき、そこから生成される型では、要素が1つも無くてもOKになっていまいます。
schema↓
const numList = yup.array().of(yup.number()).required();
//requiredで「最低1つは必要」という意味になる
numList.validateSync([]); // 失敗する
numList.validateSync([1]); //成功する
型生成↓
type NumList = yup.InferType<typeof numList>;
// 生成された型 string[]
// 本当は [string,...string[]] になってほしい
zod
schema↓
const numList = zod.number().array().nonempty();
// nonemptyで「最低1つは必要」という意味になる
numList.parse([]); // 失敗する
numList.parse(['Ariana Grande']); // 成功する
型生成↓
type NumList = zod.infer<typeof numList>
// [string,...string[]]
複雑なスキーマ定義:Yup△ zod◎
zodではunion(OR)やintersection(AND)が使えます。Yupでは使えません。
zod
const stringOrNumber = z.union([z.string(), z.number()]); //stringまたはnumber
stringOrNumber.parse('foo'); // 成功する
stringOrNumber.parse(14); // 成功する
const a = z.union([z.number(), z.string()]);
const b = z.union([z.number(), z.boolean()]);
const c = z.intersection(a, b);
type c = z.infer<typeof C>; // => number
他にも、zodのみでしか使えないものとして、tupleやFunctionなどがあります。
便利なAPIの種類:Yup◎ zod△
Yupで用意されている便利なAPIには以下のようなものがあります。
・nubmer.round
:切り捨て、四捨五入、切り上げができる
・object.camelCase
:objectのすべてのkeyをcamelCaseにする
・string.trim
:最初と最後の空白を取り除く
zodはあまりAPIが用意されていません。
まとめ
今回はバリデーションライブラリを紹介していきました。さらに、Yupとzodを中心に比較してみました。
zodはこれからどんどん便利なAPIが追加されていきそうですが、便利なAPIが用意されていればいるほどファイルサイズが大きくなってしまうので、ファイルサイズが小さいというメリットは失われるかもしれません。ですが、TypeScriptの恩恵を受けるためにはzodを使った方が良いと思います。
弊社の開発しているpalanKitというサービスではBlitz.jsを使っているのでzodを使用しています。zodのおかげでクライアント側、サーバー側で同じ型定義を使い回すことができるので気に入っています。
また、今回あまり触れなかったVestは書き方が独特で気になっています。コードを見ると、まさにテストツールの書き方になっています。
import vest, { test } from 'vest';
export default vest.create('user_form', (data = {}, currentField) => {
vest.only(currentField);
test('username', 'Username is required', () => {
enforce(data.username).isNotEmpty();
});
test('username', 'Username is too short', () => {
enforce(data.username).longerThanOrEquals(3);
});
test('tos', () => {
enforce(data.tos).isTruthy();
});
});
Vestで型生成も対応したらぜひ取り入れてみたいと思います。
Reactのお仕事に関するご相談
Bageleeの運営会社、palanではReactに関するお仕事のご相談を無料で承っております。
zoomなどのオンラインミーティング、お電話、貴社への訪問、いずれも可能です。
ぜひお気軽にご相談ください。
この記事は
参考になりましたか?
4
1
関連記事
2022年5月13日
Reactでオセロゲームを作る
2021年4月9日
Slack OAuth x React で Slack ユーザー認証を作ってみた!
2021年3月1日
Reactで使えるバリデーションライブラリを紹介!
2021年2月22日
Hasura Cloud × Auth0 × React でお手軽にTodoアプリを作ってみた!
2020年12月12日
Blitz.jsとTailwind CSSでメモ帳アプリの作成【第2弾】
2020年12月8日
コンポーネントを実装するときに意識すること
簡単に自分で作れるWebAR
「palanAR」はオンラインで簡単に作れるWebAR作成ツールです。WebARとはアプリを使用せずに、Webサイト上でARを体験できる新しい技術です。
palanARへpalanでは一緒に働く仲間を募集しています
正社員や業務委託、アルバイトやインターンなど雇用形態にこだわらず、
ベテランの方から業界未経験の方まで様々なかたのお力をお借りしたいと考えております。
運営メンバー
Eishi Saito 総務
SIerやスタートアップ、フリーランスを経て2016年11月にpalan(旧eishis)を設立。 マーケター・ディレクター・エンジニアなど何でも屋。 COBOLからReactまで色んなことやります。
sasakki デザイナー
アメリカの大学を卒業後、日本、シンガポールでデザイナーとして活動。
やまかわたかし デザイナー
フロントエンドデザイナー。デザインからHTML / CSS、JSの実装を担当しています。最近はReactやReact Nativeをよく触っています。
Sayaka Osanai デザイナー
Sketchだいすきプロダクトデザイナー。シンプルだけどちょっとかわいいデザインが得意。 好きな食べものは生ハムとお寿司とカレーです。
はらた エンジニア
サーバーサイドエンジニア Ruby on Railsを使った開発を行なっています
こぼり ともろう エンジニア
サーバーサイドエンジニア。SIerを経て2019年7月に入社。日々学習しながらRuby on Railsを使った開発を行っています。
ささい エンジニア
フロントエンドエンジニア WebGLとReactが強みと言えるように頑張ってます。
Damien
WebAR/VRの企画・開発をやっています。森に住んでいます。
ゲスト bagelee
かっきー
まりな
suzuki
miyagi
ogawa
雑食デザイナー。UI/UXデザインやコーディング、時々フロントエンドやってます。最近はARも。
いわもと
デザイナーをしています。 好きな食べ物はラーメンです。
taishi kobari
フロントエンドの開発を主に担当してます。Blitz.js好きです。
kubota shogo
サーバーサイドエンジニア。Ruby on Railsを使った開発を行いつつ月500kmほど走っています!
nishi tomoya
aihara
グラフィックデザイナーから、フロントエンドエンジニアになりました。最近はWebAR/VRの開発や、Blender、Unityを触っています。モノづくりとワンコが好きです。
nagao
SIerを経てアプリのエンジニアに。xR業界に興味があり、unityを使って開発をしたりしています。
Kainuma
サーバーサイドエンジニア Ruby on Railsを使った開発を行なっています
sugimoto
asama
ando
iwasawa ayane
oshimo
異業界からやってきたデザイナー。 palanARのUIをメインに担当してます。 これからたくさん吸収していきます!