型ガード(Type Guard)とはif文やcase文をはじめとした条件分岐で変数の型を判別し、ブロック内の変数の型を絞り込む機能のことをいいます。
型の絞り込みをすることでブロック内の変数の型が特定されるため、型のキャスト(型を明示して変換すること)が不要になります。
今回は複数の型をもつ可能性のあるUnion型の変数の型を絞り込む方法について紹介します。
typeofを利用する
typeof
はプリミティブ型を判別する型ガード演算子です。
プリミティブ型のUnion型はtypeof
で型を絞り込めます。
const convert = (value: string | number): string => {
if (typeof value === 'string') {
return value.toUpperCase(); // string型と推論される
} else {
return value.toString(); // number型と推論される
}
}
console.log(convert('hoge'))
// "HOGE"
console.log(convert(123))
// "123"
typeofの詳細解説は【TypeScript】型ガード(タイプガード)の概要。typeofとinstanceofの利用例で紹介しています。
instanceofを利用する
instanceof
はクラスを判別する型ガード演算子です。
クラスのUnion型はinstanceof
でクラスを絞り込めます。
class Cat {
name: string
meow: string
constructor(name: string, meow: string) {
this.name = name
this.meow = meow
}
}
class Duck {
name: string
quack: string
constructor(name: string, quack: string) {
this.name = name
this.quack = quack
}
}
type Animal = Cat | Duck
const say = (animal: Animal): string => {
if (animal instanceof Cat) {
return animal.meow // Catクラスと推定される
} else {
return animal.quack // Duckクラスと推定される
}
}
const tama = new Cat('Tama', 'meow!!meow!!')
const shiro = new Duck('Shiro', 'quack!!quack!!')
console.log(say(tama))
// "meow!!meow!!"
console.log(say(shiro))
// "quack!!quack!!"
instanceofの詳細解説は【TypeScript】型ガード(タイプガード)の概要。typeofとinstanceofの利用例で紹介しています。
ユーザー定義型ガードを利用する
ユーザー定義型ガードとは型ガードの役割をはたす関数のことです。
ユーザー定義型ガードの戻り値は引数 is 型
(型述語、Type Predicate)です。
戻り値が引数 is T
の場合、「trueなら引数は型T、falseなら型Tではない」という挙動になります。
const isString = (value: string | number): value is string => {
return typeof value === "string";
}
const convert = (value: string | number): string => {
if (isString(value)) {
return value.toUpperCase(); // string型と推論される
} else {
return value.toString(); // number型と推論される
}
}
console.log(convert('hoge'))
// "HOGE"
console.log(convert(123))
// "123"
なお、ユーザー定義型ガードおよびis(Type Predicate)の詳細解説はTypeScpirtのis(Type Predicate)を使ってユーザー定義型ガードを実装するで紹介しています。
inを利用する
inを利用することでオブジェクトのプロパティの有無を判定できます。
この機能を活用するとin
で型の絞り込みができます。
typeof
が利用できない独自定義の型ではin
による型の絞り込みが有効です。
type Cat = {
name: string;
meow: string;
}
type Duck = {
name: string;
quack: string;
}
type Animal = Cat | Duck;
const say = (animal: Animal): string => {
if ('meow' in animal) {
return animal.meow // Cat型と推論される
} else {
return animal.quack // Duck型と推論される
}
}
const tama: Cat = {
name: 'Tama',
meow: "meow!!meow!!"
}
const shiro: Duck = {
name: 'Shiro',
quack: "quack!!quack!!"
}
console.log(say(tama))
// "meow!!meow!!"
console.log(say(shiro))
// "quack!!quack!!"
なお、inを利用した型の絞り込みの詳細解説は【TypeScript】inを利用して型の絞り込みを行う方法で紹介しています。
さいごに
Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!