TypeScript - Type Guard
公開日:2019-02-11 更新日:2019-05-14
1. 概要
途中から変数の型を特定して、キャストせずに、個別のメソッドを実行できるようにします。
C#では、変数 obj が Car クラスだった場合、car と言う新しい変数を生成して、
if の中では変数 car を Carクラス として使用することができます。
TypeScript の場合、
typeof でもクラスの特定ができないため(object かどうかしかわからない)、
Type Guard と言う仕組みを使って、ソースの途中から、型を絞り込むことができます。
これにより、エディターによっては、インテリセンス(自動補完)による入力支援も使えます。
C#では、変数 obj が Car クラスだった場合、car と言う新しい変数を生成して、
if の中では変数 car を Carクラス として使用することができます。
if (obj is Car car) {
car.drive();
}
TypeScript の場合、
typeof でもクラスの特定ができないため(object かどうかしかわからない)、
Type Guard と言う仕組みを使って、ソースの途中から、型を絞り込むことができます。
これにより、エディターによっては、インテリセンス(自動補完)による入力支援も使えます。
function 関数名(変数名: 型): 変数名 is 特定された型 {
return true; //true の場合、引数の変数が、「特定された型」として扱われる
}
//呼び出し側
if (関数(変数)) {
//この中では「特定された型」として使用できる
変数.メソッド();
}
2.1 サンプル
class Dog {
public name: string = "犬";
public run(): string {
return;
}
}
function isDog(creature: any): creature is Dog {
//typeof でクラスを判定できないため、メソッドの有無でクラスを判定します
return (<Dog>creature).run !== undefined;
}
function getName(creature: any): void {
if (isDog(creature)) {
//このブロックの中では、creature は Dogクラスとして扱える
console.log(creature.name);
} else {
console.log("未知の生物");
}
}
getName({ a: 5 }); //未知の生物
getName(new Dog()); //犬
2.2 サンプル
//植物
class Plant {
public seed; //種
}
//動物
class Animal { }
//犬
class Dog extends Animal {
public run(): string {
return "犬";
}
}
//鳥
class Bird extends Animal {
public fly(): string {
return "鳥";
}
}
function isDog(creature: Animal | Plant): creature is Dog {
return (<Dog>creature).run !== undefined;
}
function isPlant(creature: Animal | Plant): creature is Plant {
return (<Plant>creature).seed !== undefined;
}
function test(creature: any) {
if (isDog(creature)) {
let s = creature.run();
console.log(s);
return;
}
if (isPlant(creature)) {
let s = creature.seed;
console.log("植物:" + s);
return;
}
console.log("該当なし");
}
test(new Dog); //犬
test(new Bird); //該当なし
test(new Plant); //該当なし
let plant = new Plant();
plant.seed = 5;
test(plant); //植物:5
2.3 サンプル - Type Guard と instanceof の違い
instanceof では interface の判定が行えない点と、
変数の型が特定済みの場合は、instanceof で判定をしても、定義した時点の型として扱われます。
変数の型が特定済みの場合は、instanceof で判定をしても、定義した時点の型として扱われます。
class Animal { v1: number; }
class Dog extends Animal { v2: number; }
function test(obj: any) {
if (obj instanceof Animal) {
console.log(obj.v1);
//ビルドエラー
//obj は Animal として扱われる
//console.log(obj.v2);
}
}
let obj = new Dog();
obj.v1 = 5;
obj.v2 = 10;
test(obj);
if (obj instanceof Animal) {
console.log(obj.v1);
//エラーにならない
//obj は Dog のまま扱われる
console.log(obj.v2);
}