型の絞りこみ~型ガード編①~【個人学習まとめ】
型ガード
前回の記事で型の絞り込みが 2 種類あることを学習しました。
その 2 種類のうち、型ガードについて今回の記事から学習しましょう。
等価性による絞り込み
型を絞り込むために、等価演算子(===
、!==
、==
、!=
)を利用することができます。
if 文や switch 文を使った利用方法を確認してみましょう。
let test1 = Math.random() > 0.5 ? 1 : "HELLO";
if (test1 === "HELLO") {
console.log(test1.toLowerCase());
→ hello
}
test1.substring(3);
→ プロパティ 'toLowerCase' は型 'string | number' に存在しません。プロパティ 'toLowerCase' は型 'number' に存在しません。
上記の if 文では、変数test1
の値がHELLO
型である場合にtrue
となりconsole
が実行されます。
この if 文のスコープ内では、変数test1
はstring
型(HELLO
型から型の拡大がされる)であると TypeScript が理解しているため、toLowerCase
メソッドを呼び出すことができます。
しかし、スコープの外にあるsubstring
メソッドを呼び出そうとてしても、変数test1
の型はstring | number
であるため TypeScript はエラーを表示します。
もう一つ別のパターンを見てみましょう。
function testFunction(strOrNum: string | number, strOrBool: string | boolean) {
if (strOrNum === strOrBool) {
//どちらもstring型(かつ引数の値が一致している)の場合に真となる
console.log(strOrNum.toLowerCase());
console.log(strOrBool.toLowerCase());
} else {
//どちらかがstring型以外の場合に偽となる
console.log("どちらかがfalseの場合");
console.log(strOrNum);
console.log(strOrBool);
}
}
if 文の条件式で型の等価性を評価した後は、引数strOrNum
とstrOrBool
はそれぞれstring
型であることを TypeScript は理解するので、toLowerCase
メソッドを呼び出すことができます。
仮にtestFunction
関数のトップレベルで、それぞれの引数に対してtoLowerCase
メソッドを呼び出しても TypeScript は引数がstring
型なのか、number
型なのか、boolean
型なのか理解できていないためエラーになります。
function testFunction(strOrNum: string | number, strOrBool: string | boolean) {
strOrNum.toLowerCase();
→ プロパティ 'toLowerCase' は型 'string | number' に存在しません。
プロパティ 'toLowerCase' は型 'number' に存在しません。
strOrBool.toLowerCase();
→ プロパティ 'toLowerCase' は型 'string | boolean' に存在しません。
プロパティ 'toLowerCase' は型 'false' に存在しません。
if (strOrNum === strOrBool) {
...
typeof による絞り込み
typeof
演算子は型を返す式です。
typeof
typeof ○○○
とすると指定した値の型を確認することができます。
function checkValueType(value: string | number) {
if (typeof value === "string") {
console.log("string型です。");
console.log(value.toLowerCase());
} else {
console.log(value.toFixed());
}
}
checkValueType("MOJIRETSUDAYO");
→ mojiretsudayo
checkValueType(3.141592653589);
→ 3
上記の例ではtypeof
演算子を使って引数value
がstring
型であるかどうかをチェックします。
if 文が真となった場合は、value
の値がstring
型であることが保証され、toLowerCase
メソッドを呼び出すことができます。
if 文が偽となった場合は、引数value
の値がnumber
型である。と TypeScript が推論し、toFixed
メソッドを呼び出すことができます。
in 演算子による絞り込み
in
演算子は、指定したオブジェクトが特定のプロパティを保持しているかどうかチェックする演算子です。特定のプロパティを保持している場合はtrue
を返します。
in 演算子
"プロパティ名" in オブジェクト
とするとチェックできます。
interface Circle {
radius: number;
}
interface Square {
width: number;
height: number;
}
const pi = 3.14;
function getArea(shape: Circle | Square) {
if ("radius" in shape) {
console.log("円の面積は・・・");
console.log(shape.radius * shape.radius * pi);
} else {
console.log("四角形の面積は・・・");
console.log(shape.width * shape.height);
}
}
const circleObject: Circle = { radius: 2 };
const squareObject: Square = { width: 3, height: 5 };
getArea(circleObject);
getArea(squareObject);
上記のgetArea
関数では、引数shape
がCircle
型かSquare
型のユニオン型として定義されています。
if 文にて"radius" in shape
と条件を指定しています。ここでは、引数shape
オブジェクトにradius
というプロパティが含まれているかチェックしています。
ここで真となれば、引数shape
の型はCircle
型に絞り込まれ、円の面積の計算が実行されます。
偽となれば引数shape
の型はSquare
となるので、四角形の面積の計算が実行されます。
instateof による絞り込み
instateof
演算子は、対象のオブジェクトが特定のクラスのインスタンスであるかどうか判定します。
class Bird {
fly() {
console.log("飛ぶ");
}
}
class Fish {
swim() {
console.log("泳ぐ");
}
}
function move(animal: Bird | Fish) {
if (animal instanceof Bird) {
animal.fly();
} else {
animal.swim();
}
}
const suzume = new Bird();
const ayu = new Fish();
move(suzume);
→ 飛ぶ
move(ayu);
→ 泳ぐ
上記のmove
関数では、引数にBird
型またはFish
型のインスタンスが渡されることを想定しています。
if 文にてanimal instanceof Bird
と条件を指定しています。ここでは引数animal
がBird
のインスタンスであるかどうかチェックしています。
真となればBird
クラスのコンストラクタfly
メソッドを実行することができます。
偽であれば引数animal
のインスタンスはFish
に絞り込まれるためswim
メソッドを実行することができます。
今回はここまで、もう少し型ガードにはもう少し種類があるので続いて学習していきましょう。
Discussion