この記事でできるようになること
以下の引数arrのように2つの異なる型の配列をUnion型として持つ値
をどちらの型の配列かを判定し、その結果をもとに条件分岐し型ごとに処理を分けることができる
type Hoge = {
type:'A',
id:number,
name:string;
}
type Fuga = {
type:'B',
id:number
}
const sample = (arr:Hoge[]|Fuga[])=>{
????
if(????){
console.log(arr[0].type) // => A
}else{
console.log(arr[0].type) // => B
}
}
方法
結論
user-defined typeguard
を用いて次のような判定用の関数を作成すれば良い
const isHogeArr = (item:any): item is Hoge[] => item[0].type === 'A';
type Hoge = {
type:'A',
id:number,
name:string;
}
type Fuga = {
type:'B',
id:number
}
const sample = (arr:Hoge[]|Fuga[])=>{
const isHogeArr = (item:Hoge[]|Fuga[]): item is Hoge[] => item[0].type === 'A';
if(isHogeArr(arr)){
// arr はHoge[]と判定される
console.log(arr[0].type) // => 'A'
console.log(arr[0].name) // => errorなし
}else{
// arr はFuga[]と判定される
console.log(arr[0].type) // => 'B'
console.log(arr[0].name) // => error Fugaにはnameプロパティは存在しないため
}
}
説明
そもそもuser-defined type guard
って?
関数の戻り値の型に 引数 is 型
としてTypeScriptに型を教えてあげる機能。
TypeScriptは関数の戻り値がtrueなら引数の型は上記で指定した型
と認識し、 falseなら指定した型ではない
と認識する
今回の使い方
今回はsample関数の引数として渡されたarrがHogeの配列なのか、Fugaの配列なのかを判定したい。そこで引数 is Hoge[]
となる判定関数を作る。
この際戻り値を決める条件式に関しては、
arrがHoge[]の時だけtrueにしたいので、HogeとFugaで共通して持つが値は異なるtypeプロパティを配列の先頭の要素から取得して評価する。
Hogeの時は,type==='A'
なので戻り値はtrueになる。従ってTypeScriptはisHogeArrの戻り値(引数)の型はHoge[]であると判断する。
const isHogeArr = (item:Hoge[]|Fuga[]): item is Hoge[] => item[0].type === 'A';
その他の使い道
自分がuser-defined type guard
を最初に知ったのは、型が(string | undefined)[]
な配列からundefinedを取り除く処理の書き方を学んだ時だった。
例えば、以下のような処理をした時は、resultの結果は(string | undefined)[]
になる。
const arr = ['A','B','C']
const result = ['A','B'].map(item => arr.find( i => i ===item))
ここからundefinedを取り除こうとfilterメソッドを使ってもundefinedを取り除くことはできない
const result2 = result.filter(item => item !== undefined)
// => (string | undefined)[]
user-defined type guard
を使うとこれを解決できる
次のような判定関数をかくと、result3はstring[]になる
const isNotUndefined = (item:string|undefined):item is string => { return item!==undefined}
const result3 = result.filter(isNotUndefined)
// => string[]