2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[TypeScript] 配列のUnion (e.g. A[ ] | B[ ] ) を型として持つ値がどちらの配列なのかを判定する方法

Last updated at Posted at 2022-02-11

この記事でできるようになること

以下の引数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[]

参考

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?