ウェブエンジニア珍道中

日々の技術的に関する経験を書いていきます。脱線もしますが助けになれば幸いです。

typescriptのuniontypesについて

typescriptの共用体型についてまとめてみます。

共用体型とは

union typeとか、ユニオン型とか言われてるっぽいです。

変数等に型を指定する時に複数指定できます。

複数の型を|区切りで指定し、どれかの型で有ることを示します。

こんな感じ。

let hoge: string | number; // 整数か文字列
let fuga: string;

hoge = "foo"; // OK
fuga = "foo"; // OK

hoge = 1000; // OK
fuga = 1000; // エラー

fugaは文字列のみ指定しているので整数を入れるとトランスパイル時にエラーを吐きます。

error TS2322: Type '1000' is not assignable to type 'string'.

hogeにはstringかnumberを指定しているので、文字列・数字のどちらを入れても問題ありません。

クラスの場合

自分で作った型も両方入る変数を定義できます。

class Hoge {}
class Fuga {}

let hoge: Hoge | Fuga;

hoge = new Hoge();
hoge = new Fuga();

配列の場合

数字と文字列がゴチャゴチャに入った配列をループしたいなあ。って時はこんな感じです。

const hoges: Array<number | string> = [1, 2, "hoge", 3, "fuga"];

hoges.forEach((hoge: number | string) => {
    console.log(hoge);
});

配列の型を同じ要領で複数指定すれば良いです。

型による分岐

こんな感じでAクラスとBクラスそれぞれのインスタンスが入った配列をループで回そうとするとエラーを吐きます。

class A {
    a_method() {}
}

class B {
    b_method() {}
}

const array: Array<A | B> = [new A(), new B()];

array.forEach((obj: A | B) => {
    obj.a_method(); // トランスパイルエラー
});
error TS2339: Property 'a_method' does not exist on type 'A | B'.
  Property 'a_method' does not exist on type 'B'.

a_methodを持ってないBクラスのインスタンスが回ってくる可能性があるので、実行時にトランスパイル時にエラーを吐いてくれます、ありがたいです。型も良いものですね(Ruby畑出身)

対処法としてはクラスで分岐してやればOKです。

class A {
    a_method() {}
}

class B {
    b_method() {}
}

const array: Array<A | B> = [new A(), new B()];

array.forEach((obj: A | B) => {
    if(obj instanceof A) {
        obj.a_method(); // Aクラスの時のみ通るようにする
    }
});

これでトランスパイルが通ります。

Hoge | Fuga | Foo | Bar と指定すれば3つ以上も指定できるので、「やっべぇ入んねえ」とanyに逃げずに済むのでとてもありがたいです。