TypeScriptでオブジェクトのネスト構造をバリデーションする方法を徹底解説!初心者向けデータチェック入門
生徒
「TypeScriptで、オブジェクトの中にさらにオブジェクトが入っているような、複雑なデータの形をチェックする方法はありますか?」
先生
「TypeScriptでは、データの形を定義する型機能と、プログラムの実行中に中身を検査するバリデーションという仕組みを組み合わせることで、ネスト構造のデータも安全にチェックすることができます。」
生徒
「ネスト構造やバリデーションという言葉自体が少し難しそうですが、具体的にはどのようにおこなうのですか?」
先生
「パソコンの操作やプログラミングが初めての方でも絶対に理解できるように、基礎知識から具体的な書き方まで順番に見ていきましょう!」
1. バリデーションとネスト構造とは?
プログラミングの世界では、入力されたデータが正しい形式かどうかを検査することをバリデーション(データ妥当性確認)と呼びます。例えば、インターネットで会員登録をするときに、メールアドレスの欄に文字が入力されていなかったり、年齢の欄に文字が入力されていたりすると、エラー画面が表示されます。これがバリデーションの役割です。
次に、オブジェクトとは、いくつかのデータを一つにまとめた箱のようなものです。例えば、ある利用者の名前と年齢を一つの箱に入れたデータです。そして、ネスト構造(入れ子構造)とは、その箱の中に、さらに別の箱が入っている状態を指します。具体的には、利用者の情報という大きな箱の中に、住所という別の小さな箱が入っており、その住所の箱の中に都道府県や郵便番号が記録されているような形です。
TypeScriptは、このオブジェクトの形を事前に決めておくことができるプログラミング言語ですが、インターネットから送られてくるデータが本当にその形をしているかどうかは、プログラムを実行してみないとわかりません。そのため、ネスト構造を持つ複雑なデータに対しても、しっかりと中身をチェックするバリデーションが必要不可欠になります。
2. 最も基本となるバリデーションの仕組み
データを確認する最も単純な方法は、条件分岐をおこなう命令を使うことです。データの種類を調べるための専用の命令を組み合わせて、一つ一つの項目が正しいかどうかを順番に確認していきます。
まずは、ネスト構造になっていない、非常にシンプルなオブジェクトのデータチェックをおこなうプログラムの例を見てみましょう。パソコンのキーボードを入力したことがない方でも、どのような流れでチェックが進むのかを意識しながらコードを眺めてみてください。
let user = {
name: "山田太郎",
age: 25
};
if (typeof user.name === "string" && typeof user.age === "number") {
console.log("ユーザーのデータ形式は正しいです。");
} else {
console.log("ユーザーのデータ形式にエラーがあります。");
}
上記のプログラムを実行すると、画面には次のように出力されます。これがプログラムの実行結果です。
ユーザーのデータ形式は正しいです。
ここで使用している特別な命令について解説します。typeofという命令は、データの種類が何であるかを調べるためのものです。文字データであれば「文字列」を意味する文字が返され、数字データであれば「数値」を意味する文字が返されます。そして、二つの条件を結んでいる記号は、左右の条件がどちらも成り立っていることを確認するためのものです。これらを組み合わせることで、名前が文字であり、かつ年齢が数値であることを確認しています。
3. ネスト構造を持つオブジェクトを自力でチェックする方法
基礎がわかったところで、いよいよ本題であるネスト構造を持つオブジェクトのバリデーションに挑戦します。大きな箱の中に小さな箱が入っているため、外側の箱をチェックした後に、内側の箱の中身も同じように細かく調べていく必要があります。
今回は、利用者の情報の中に、住所の情報が丸ごと入っているネスト構造のデータを想定します。住所の箱自体が存在しているかどうか、そしてその中の都道府県や市町村のデータが正しい種類かどうかを、慎重に確認するプログラムを作成します。
let customer = {
id: 101,
profile: {
cityName: "大阪市",
zipCode: "1234567"
}
};
if (
typeof customer.id === "number" &&
customer.profile !== null &&
typeof customer.profile === "object" &&
typeof customer.profile.cityName === "string" &&
typeof customer.profile.zipCode === "string"
) {
console.log("ネストされた住所データもすべて正常です。");
} else {
console.log("データに不備があります。");
}
上記のプログラムを実行した際の出力結果は以下のようになります。
ネストされた住所データもすべて正常です。
このプログラムでは、内側の箱を確認する前に、特殊な判定を入れています。何もデータが入っていない空っぽの状態を表す値ではないこと、そしてそのデータ自体がオブジェクトという箱の形をしていることを確認しています。この手順を踏まないと、内側のデータを調べようとした瞬間にプログラムが強制終了してしまう原因になります。安全に処理を進めるために、外側から内側へと順番に確認をおこなっていくのが、ネスト構造のバリデーションの鉄則です。
4. 関数を使ってバリデーションを部品化する
先ほどのように条件分岐を何行も書く方法は、確認する項目が多くなるとプログラムが非常に長くなってしまい、読みづらくなります。また、同じようなチェックを何度もやりたいときに、何度も同じ命令を書くのは大変です。そこで、一連のチェック処理を一つの部品としてまとめる仕組みを使います。この部品のことを関数と呼びます。
関数を作っておけば、必要なときにその部品を呼び出すだけで、いつでも同じデータチェックを実行できるようになります。今回は、商品の情報の中に詳細なスペック情報がネストされているオブジェクトを判定する部品を作ってみましょう。
function validateProduct(item: any): boolean {
if (!item || typeof item !== "object") {
return false;
}
if (typeof item.title !== "string") {
return false;
}
if (!item.detail || typeof item.detail !== "object") {
return false;
}
if (typeof item.detail.price !== "number") {
return false;
}
return true;
}
let laptop = {
title: "高性能パソコン",
detail: {
price: 150000
}
};
if (validateProduct(laptop)) {
console.log("商品データのチェックに合格しました。");
} else {
console.log("不適切な商品データです。");
}
上記のプログラムを実行すると、画面には次のように表示されます。
商品データのチェックに合格しました。
このプログラムでは、条件に合わない不適切なデータが見つかった時点で、すぐに処理を終了して「失敗」という結果を返しています。このように、正しくないものを先にはじいていく書き方をすると、ネストが深く複雑な構造であっても、プログラムの見た目がすっきりとして分かりやすくなります。
5. 型安全性を高めるための発展的な型チェック
TypeScriptの大きな特徴は、開発者がデータの設計図をあらかじめ定義できる点にあります。これによって、打ち間違いなどの初歩的なミスをパソコンが自動的に指摘してくれるようになります。バリデーションをおこなう際も、この設計図の機能を活用することで、より安全にプログラムを動かすことができます。
ここでは、会社とそこで働く従業員のデータを想定します。会社オブジェクトの中に、従業員オブジェクトがネストされている構造です。設計図を定義した上で、データがその設計図通りになっているかを検査する仕組みを作成します。
type WorkerInfo = {
employeeName: string;
};
type CompanyGroup = {
groupName: string;
staff: WorkerInfo;
};
function isCompanyGroup(data: any): data is CompanyGroup {
return (
data &&
typeof data.groupName === "string" &&
data.staff &&
typeof data.staff.employeeName === "string"
) ? true : false;
}
let targetData = {
groupName: "開発部",
staff: {
employeeName: "佐藤さくら"
}
};
if (isCompanyGroup(targetData)) {
console.log("設計図通りの正しいデータ構造であることが証明されました。");
}
上記のプログラムを実行した結果の表示は以下の通りです。
設計図通りの正しいデータ構造であることが証明されました。
このプログラムの中で登場する特殊な書き方は、このチェックを通過したデータは、指定した設計図通りのデータとして扱ってよい、ということをTypeScriptに伝えるためのものです。これをおこなうことで、バリデーションを行った後のプログラムにおいて、データの中身を完全に信頼して次の処理に進めるようになります。
6. ネスト構造のバリデーションにおける注意点とトラブル対策
ネスト構造を持つオブジェクトのバリデーションを自分でおこなうとき、初心者が最もやってしまいがちな失敗があります。それは、外側の箱が存在しているかどうかを確認する前に、内側の箱のデータを読み取ろうとしてしまうことです。これをやってしまうと、プログラムが途中で完全に停止してしまいます。
例えば、インターネット通信の不具合や入力漏れによって、内側のオブジェクトが丸ごと省略されてしまうケースがあります。そのような場合でもプログラムが壊れないようにするために、常にデータが存在しない可能性を頭に入れておかなければなりません。未経験の方がプログラムを書くときは、必ず手前の段階でデータの有無を確認する癖をつけておくと、エラーの起きにくい素晴らしいプログラムが書けるようになります。