目次
おさらい: プリミティブ型の型ガードの実装方法
JavaScriptのデータ型にはプリミティブ型とオブジェクトがあります。
プリミティブ型の型ガードは、プリミティブ型を判別するtypeof
演算子を利用することで実装できます。
以下はtypeof
演算子を利用してstring型とnumber型を判別する例です。
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"
プリミティブ型の詳細解説は【JavaScript】データ型(プリミティブ型とオブジェクト)、リテラルに関する基礎知識で紹介しています。
型ガードの詳細解説は【TypeScript】型ガード(Type Guard)の概要、typeofとinstanceofの利用例で紹介しています。
オブジェクトの型ガード
以下ではオブジェクトの型ガードの実装方法について紹介します。
利用するサンプルコード
CatType型とDuckType型が存在しています。
このとき、CatType型のオブジェクトであればmeow
プロパティを、DuckType型のオブジェクトであればquack
プロパティを参照するメソッドを考えます。
type CatType = {
name: string
meow: string
}
type DuckType = {
name: string
quack: string
}
type AnimalType = CatType | DuckType
// tama は CatType か DuckType のどちらか
const tama: AnimalType = { name: 'Tama', meow: 'meow!!meow!!' }
// ahiru は CatType か DuckType のどちらか
const ahiru: AnimalType = { name: 'Ahiru', quack: 'quack!!quack!!') }
// 以下のような結果になるsayメソッドを作成したい
say(tama) // meow!!meow!!
say(ahiru) // quack!!quack!!
方法1: オブジェクトの各プロパティの型をtypeofで確認する
オブジェクトの各プロパティの型をtypeof
で判定し、型の絞り込みをする方法です。
具体的なコードは以下の通りです。
const say = (animal: any): void => {
if (typeof animal.name === "string" && typeof animal.meow === "string") {
// nameとmeowプロパティの型が意図したものであるならCatType型なはず
console.log(animal.meow)
} else if (typeof animal.name === 'string' && typeof animal.quack === 'string') {
// nameとquackプロパティの型が意図したものであるならDuckType型なはず
console.log(animal.quack)
}
}
ユーザー定義型ガードを利用して書き直すと以下のようになります。
ユーザー定義型ガードの詳細解説はTypeScriptのis(Type Predicate)を使ってユーザー定義型ガードを実装するで紹介しています。
// trueならCatType型と推定される
const isCatType = (animal: any): animal is CatType =>
typeof animal.name === "string" && typeof animal.meow === "string"
// trueならDuckType型と推定される
const isDuckType = (animal: any): animal is DuckType =>
typeof animal.name === 'string' && typeof animal.quack === 'string'
const say = (animal: any): void => {
if (isCatType(animal)) {
console.log(animal.meow)
} else if (isDuckType(animal)) {
console.log(animal.quack)
}
}
なお、sayメソッドの引数をany型以外で受けたいのであれば以下のように型アサーション(as
)を利用する必要があります。
type AnimalType = CatType | DuckType
const say = (animal: AnimalType): void => {
let cat = animal as CatType
let duck = animal as DuckType
if (typeof cat.name === "string" && typeof cat.meow === "string") {
console.log(cat.meow)
} else if ( typeof duck.name === 'string' && typeof duck.quack === 'string') {
console.log(duck.quack)
}
}
方法2: オブジェクトのプロパティの有無をinで確認する
JavaScriptのin
を利用することでオブジェクトのプロパティの有無が確認できます。
プロパティの種類をin
を活用して判別することで型ガードを実装できます。
in
の詳細解説は【TypeScript】inを利用して型の絞り込みを行う方法で紹介しています。
今回の場合ですと、name
とmeow
をプロパティに持つオブジェクトはCatType型、name
とquack
をプロパティに持つオブジェクトはDuckType型となります。
const say = (animal: AnimalType): void => {
if ('name' in animal && 'meow' in animal) {
// CatType型と推定される
console.log(animal.meow)
} else if ('name' in animal && 'quack' in animal) {
// DuckType型と推定される
console.log(animal.quack)
}
}
ユーザー定義型ガードを利用して書き直すと以下のようになります。
// trueならCatType型と推定される
const isCatType = (animal: AnimalType): animal is CatType =>
'name' in animal && 'meow' in animal
// trueならDuckType型と推定される
const isDuckType = (animal: AnimalType): animal is DuckType =>
'name' in animal && 'quack' in animal
const say = (animal: AnimalType): void => {
if (isCatType(animal)) {
console.log(animal.meow)
} else if (isDuckType(animal)) {
console.log(animal.quack)
}
}
さいごに
Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!