TypeScript の「ユーザー定義型ガード」(User Defined Type Guard) で、オブジェクトのデータ型を判定する方法です。
基本の形と、プロパティに配列が含まれている場合について備忘として残しておきます。
1. 一般的なオブジェクトのユーザー定義型ガード
前提として、普通のオブジェクトのユーザー定義型ガードです。
person.ts
// 判定対象のデータ型
type Person = {
name: string;
age: number;
};
sample.ts
// Person オブジェクトか否かを判定するユーザー定義型ガード
function isPerson(arg: unknown): arg is Person {
if (!arg) return false; // null, undefined の場合を除く
const person = arg as Person; // 型アサーションで Person 型とみなす
return typeof person.name === 'string' && typeof person.age === 'number';
}
型アサーション(Type Assertion)を適用した上で、person.name
および person.age
のデータ型を個別に判定しています。
2. 配列を含んだオブジェクトのユーザー定義型ガード
2-1. プロパティに文字列配列を含んでいる場合
次のように、プロパティに hobbies: string[]
という文字列配列を含んでいる場合についてです。
person.ts
// 配列を含んだデータ型
type Person = {
name: string;
age: number;
hobbies: string[];
};
sample.ts
// 配列を含むオブジェクトを判定するユーザー定義型ガード
function isPerson(arg: unknown): arg is Person {
if (!arg) return false; // null, undefined の場合を除く
const person = arg as Person; // 型アサーションで Person 型とみなす
// 配列か否かを判定
if (!Array.isArray(person.hobbies)) return false;
// 全てstring型か否かを判定
if (person.hobbies.some((v) => typeof v !== 'string')) return false;
return typeof person.name === 'string' && typeof person.age === 'number';
}
配列の判定は、次のように行っています。
① Array.isArray() メソッドで配列か否かを判定する。
② some() メソッドで、配列内の要素が全て string 型かを確認する。
<参考サイト>
・Type guards for types of arrays
2-2. プロパティにオブジェクト配列を含んでいる場合
次に、プロパティの配列の要素がオブジェクト型の場合です。
person.ts
// オブジェクトを要素とする配列を含んだデータ型
type Person = {
name: string;
age: number;
purchase: Purchase[];
};
// purchaseプロパティで使用する配列
type Purchase = {
name: string;
quantity: number;
};
考え方は文字列配列と同じですが、対象のプロパティ(purchase)についてもユーザー定義型ガードを用意して、ループ処理で判定を行います。
sample.ts
// プロパティのPurchase型を判定するユーザー定義型ガード
function isPurchase(arg: unknown): arg is Purchase {
if (!arg) return false;
const purchase = arg as Purchase;
return typeof purchase.name === 'string' && typeof purchase.quantity === 'number';
}
// 配列を含むオブジェクトを判定するユーザー定義型ガード
function isPerson(arg: unknown): arg is Person {
if (!arg) return false;
const person = arg as Person;
// 配列か否かを判定
if (!Array.isArray(person.purchase)) return false;
// 全てPurchase型か否かを判定
if (person.purchase.some((v) => !isPurchase(v))) return false;
return typeof person.name === 'string' && typeof person.age === 'number';
}