TypeScriptとYupで簡単データバリデーション!初心者向けスキーマ定義完全ガイド
生徒
「TypeScriptでユーザーに入力してもらうデータのチェックを自動で行う方法ってありますか?」
先生
「TypeScriptとYupというライブラリを組み合わせることで、安全で確実なデータバリデーションを簡単に実装することができますよ。」
生徒
「データのチェックを自動化する仕組みなんですね。具体的にはどのように使うんですか?」
先生
「それでは、パソコンを触ったことがない方でも基本からしっかり学べるように、使い方を見ていきましょう!」
1. データバリデーションとYupとは?
プログラミングの世界では、画面から入力されたデータが正しい形式かどうかを確かめる作業をデータバリデーション(入力チェック)と呼びます。例えば、お申し込み画面で年齢を入力する欄に文字が入力されていたり、必須の項目が空欄のまま送信ボタンが押されたりしたときに、「正しい値を入力してください」と警告を出す仕組みのことです。
このデータバリデーションを、型に厳しい言語であるTypeScriptで簡単かつ強力に行うために開発された道具がYup(ヤップ)というライブラリです。ライブラリとは、便利な機能があらかじめ詰め込まれたプログラムの部品集のようなものです。Yupを使うことで、データが満たすべき条件の設計図を作ることができ、その設計図に基づいて一瞬でデータを検査することが可能になります。
2. スキーマバリデーションの考え方
Yupの最大の特徴は、スキーマと呼ばれるデータの設計図を定義する点にあります。スキーマとは、データがどのような構造をしているべきか、どのような条件を満たすべきかを決めたルールブックのようなものです。例えば、「名前は文字列で必須」「年齢は数値で0以上」といったルールをあらかじめ紙に書いておくイメージです。
このルールブックを一度作っておけば、あとは新しいデータが届くたびに、そのデータがルールブック通りになっているかを自動的に審査させることができます。これをスキーマバリデーションと呼びます。型を重視するTypeScriptと非常に相性が良く、安全なウェブサイトやアプリケーションを制作する上での必須の技術となっています。
3. 最もシンプルなスキーマの定義方法
まずは、一番基本となる文字を入力するためのルールを作ってみましょう。ここでは、ユーザーの名前をチェックする仕組みを作成します。名前は必ず文字で入力してもらい、空欄は禁止にするというルールを構築します。
import * as yup from 'yup';
const nameSchema = yup.string().required();
nameSchema.validate("山田太郎")
.then(result => console.log("成功しました:", result))
.catch(error => console.log("エラー発生:", error.message));
上のプログラムを解説します。最初にYupの機能をすべて読み込んでいます。次に、yup.string()を使って「文字であること」というルールを指定し、さらに.required()を繋げることで「必須項目であること」を命令しています。最後にvalidateという命令を使って、実際にデータが合格しているかを調べています。実行結果は次のようになります。
成功しました: 山田太郎
4. 数値のチェックとエラーメッセージの変更
次に、数字を扱うルールを追加してみましょう。年齢を入力してもらう場面を想定します。年齢は数値でなければならず、さらに18歳以上でなければならないという制限をつけます。また、ルールに違反したときに表示される警告メッセージを、日本語の分かりやすい言葉に変更する方法も学びましょう。
import * as yup from 'yup';
const ageSchema = yup
.number()
.typeError("数字を入力してください")
.min(18, "18歳以上でなければ登録できません");
ageSchema.validate(15)
.then(result => console.log("合格:", result))
.catch(error => console.log("理由:", error.message));
このプログラムでは、yup.number()で「数値であること」を指定しています。typeErrorは、もし文字が入力されるなど型が間違っていたときに出す警告文です。そして.min(18, "メッセージ")と書くことで、18以上の数値であるかを判定し、満たさなかったときのエラーメッセージを自由に設定しています。今回のデータは15なので、不合格となり次の結果が出力されます。
理由: 18歳以上でなければ登録できません
5. 複数の項目をまとめるオブジェクト形式の定義
実際のウェブサイトでは、名前や年齢、メールアドレスなど、たくさんの項目を一度に送信することが一般的です。このように、複数のデータがセットになった状態のものをプログラミングではオブジェクトと呼びます。Yupを使って、このオブジェクト全体を一度に検証するルールブックを作成してみましょう。
import * as yup from 'yup';
const userFormSchema = yup.object({
userName: yup.string().required("お名前は必須です"),
userEmail: yup.string().email("正しいメールアドレスの形式ではありません").required("メールアドレスは必須です"),
userAge: yup.number().typeError("年齢は数字で入力してください")
});
const inputData = {
userName: "",
userEmail: "test-sample",
userAge: 25
};
userFormSchema.validate(inputData, { abortEarly: false })
.then(result => console.log("バリデーション成功:", result))
.catch(errors => {
console.log("不合格項目のエラー一覧:");
errors.inner.forEach((err: any) => {
console.log(err.path, ":", err.message);
});
});
複数の項目をまとめるときは、yup.object()の中にそれぞれの項目のルールを並べて書きます。メールアドレスのチェックには.email()という専用の便利な機能が用意されています。また、データの検証を行う際にabortEarly: falseという設定を付け足すことで、ひとつのエラーが見つかっても途中で検査を止めず、すべての項目の悪いところを最後まで調べて洗い出してくれるようになります。実行すると、空欄の名前と不正な形式のメールアドレスが検知されます。
不合格項目のエラー一覧:
userName : お名前は必須です
userEmail : 正しいメールアドレスの形式ではありません
6. TypeScriptの型とYupを連動させる魔法の機能
TypeScriptの最大のメリットは、プログラムが扱うデータの種類を明確にして、打ち間違いなどのミスを防いでくれる点にあります。しかし、YupのルールブックとTypeScriptの型の定義を別々に手作業で書くと、修正があったときに両方を直さなければならず、非常に面倒です。そこで、Yupのルールブックから自動的にTypeScriptの型を抽出する機能が用意されています。
import * as yup from 'yup';
const memberSchema = yup.object({
id: yup.number().required(),
nickname: yup.string().required()
});
type MemberType = yup.InferType<typeof memberSchema>;
const newMember: MemberType = {
id: 101,
nickname: "たろう"
};
console.log("型が適用されたデータ:", newMember);
ここで注目すべき部分はyup.InferType<typeof memberSchema>という記述です。この一行を書くだけで、先ほど作ったmemberSchemaというルールブックの内容を読み取り、自動的にTypeScriptが理解できる型データに変換してくれます。これにより、ルールを変更した際も一箇所を書き換えるだけで、すべてのシステムが自動的に最新の型に対応するようになり、開発の効率が劇的に向上します。
型が適用されたデータ: { id: 101, nickname: 'たろう' }