はじめに
普段からTypeScriptを使っています。
そこで、
Union Typesで複数の型を一つの型にまとめて、型の種類によって処理を分けたい
、
といった場面がありました。
使えそうな方法が2つほどありましたので、紹介していきます。
そもそも何がしたかったか具体的に
こういうことがしたかったです。
interface Hoge {
// property
}
interface Fuga {
// property
}
type Union = Hoge | Fuga;
const hoge: Hoge = {
// Hogeのプロパティ
};
const fuga: Fuga = {
// Fugaのプロパティ
};
const unionList: Union[] = [hoge, fuga];
const func = (arg: Union): Union => {
if (Hogeかどうかの判定) {
// Hoge用の処理;
} else if (Fugaかどうかの判定) {
// Fuga用の処理;
} else {
//
}
};
const listFunc = (args: Union[]): Union[] => {
const funcedArgs = args.map(arg => func(arg));
return funcedArgs;
};
後の方の関数は適当ですが、要するに、まとめた型で配列を作って、型を判定しながらそれぞれの処理を行いたい、という感じです。
では、具体的にどういう方法で型を判定したかを紹介します。
Type Guard
interface Hoge {
type: string
text: string
}
interface Fuga {
type: string
number: number
}
type Union = Hoge | Fuga
const func = (arg: Union) => {
if(isHoge(arg)){
// Hoge用の処理
// isHogeでbooleanを返すとHoge型だと認識されずtextプロパティない可能性あるよと怒られる
}else if(isFuga(arg)){
// Fuga用の処理
}else{
//
}
}
const isHoge = (arg:Union): arg is Hoge => {
return arg.type === 'Hoge'
}
const isFuga = (arg:Union): arg is Fuga => {
return arg.type === 'Fuga'
}
型の判定後に判定した値の型を確定させることができます。
ポイントは型を判定する関数の返り値の型です。
arg is Hoge
のようにしてやることで、関数の判定がtrueになったブロックでは、Hoge型として扱われます。
ここがただのBooleanだと、Hoge型として認識してくれません。
Discriminated Unions
interface Hoge {
type: 'Hoge'
text: string
}
interface Fuga {
type: 'Fuga'
number: number
}
type Union = Hoge | Fuga
const func = (arg: Union) => {
switch (arg.type){
case 'Hoge':
// Hoge用の処理
case 'Fuga':
// Fuga用の処理
default:
//
}
}
1つ目に紹介した方に比べて、型判定のための関数定義を省くことができます。
ポイントは型定義時に、type(TypeScript公式ではkind)のような、型を識別するプロパティを持たせることです。
後はswitch文で判定できます。
TypeScript3.6から追加された機能のようです。
最後に
同じようなことをしたいと思った方の参考になれば嬉しいです!
駆け足でまとめた感じがあるので、誤りあれば教えてください。
ありがとうございました!!!