型を守る
昨日書いたこの type。age はあるかどうかわかりません。
type Human = { name: string; age?: number; sex: "M" | "W"; };
age が 12 以下ならキッズだと判断する場合、以下のように書きたいですが、エラーになっちゃいます。
const chkKids = (param: Human) => param.age <= 12; //TS2532: Object is possibly 'undefined'.
undefined かもしれんから比較できませんやんって言ってきます。
キッズチェックをする前に、型の絞り込みを行う必要があります。ガードガード。
const chkKids = (param: Human) => { if (typeof param.age === "number") { return param.age <= 12; } else { return false; } }; console.log(chkKids({ name: "a", age: 13, sex: "M" })); //false console.log(chkKids({ name: "a", age: 12, sex: "M" })); //true console.log(chkKids({ name: "a", sex: "M" })); //false
number 以外をチェックし、即 return をしてもガードがかけられます。
number 以外で return したら 後は number しかないからね。
const chkKids = (param: Human) => { if (typeof param.age !== "number") { return false; } return param.age <= 12; }; console.log(chkKids({ name: "a", age: 13, sex: "M" })); //false console.log(chkKids({ name: "a", age: 12, sex: "M" })); //true console.log(chkKids({ name: "a", sex: "M" })); //false
ただ、これぐらいなら三項演算子でもできますね。
const chkKids = (param: Human) => typeof param.age !== "number" ? false : param.age <= 12; console.log(chkKids({ name: "a", age: 13, sex: "M" })); //false console.log(chkKids({ name: "a", age: 12, sex: "M" })); //true console.log(chkKids({ name: "a", sex: "M" })); //false
ユーザ定義の型ガード
type で定義した型は、typeof で判断できません。
上記の Human 型かどうか判断するためには、ユーザ定義の型ガードを使います。
const isHuman = (human: object): human is Human => { const h = human as Human; return ( typeof h?.name === "string" && typeof h?.sex === "string" && (typeof h?.age === "number" || typeof h?.age === "undefined") ); }; console.log(isHuman({ name: "a", age: 13, sex: "M" })); //true console.log(isHuman({ name: "a", age: 12, sex: "M" })); //true console.log(isHuman({ name: "a", sex: "M" })); //true console.log(isHuman({ name: "a" })); //false
human is Human の部分。この関数の型が true を返した場合、この引数は Human だよって絞り込んでくれます。
return で true を返すには、Human 型をそれぞれチェックをかかける必要がありますが、human?.name でチェックすることはできません。
引数 human には name があるか判断できないから。
ってことで、これは Human 型なんやでぇ!と強制的にキャストする型アサーション(Deep Dive)を使っています。
const h = human as Human;
これでコンパイラに認識させることができたので、それぞれの型をチェックして return。これで Human 型かどうかを確かめる関数ができました。
type Human = { name: string; age?: number; sex: "M" | "W"; }; const isHuman = (human: object): human is Human => { const h = human as Human; return ( typeof h?.name === "string" && typeof h?.sex === "string" && (typeof h?.age === "number" || typeof h?.age === "undefined") ); }; const chkKids = (param: object) => { if (!isHuman(param)) return false; return typeof param.age !== "number" ? false : param.age <= 12; }; console.log(chkKids({ name: "a", age: 13, sex: "M" })); //false console.log(chkKids({ name: "a", age: 12, sex: "M" })); //true console.log(chkKids({ name: "a", sex: "M" })); //false console.log(chkKids({ name: "a" })); //false
chkKids の引数を object で受け取りましたが、isHuman で Human 型に絞り込んでいるので、キッズチェックをすることができます。 終わり!