FlowtypeでPhantom Typeを楽しむ

久しぶりに[Flowtype](http://flowtype.org/)を触ってみると[型の表現力が上がってました。](http://flowtype.org/blog/2015/03/12/Bounded-Polymorphism.html)
[Changelog](https://github.com/facebook/flow/blob/master/Changelog.md)を見ると他にもいろいろ遊びがいがある変更が入っているようです。（Changelogにしか載ってない情報とかあるので必読です）

これはもうPhantom Typeというカッコいい名前の型で遊ぶしかないですね！！

## Phantom Type

* [Phantom Type in Scala](http://www.slideshare.net/maedaunderscore/phatom-type-14612078#4)

とりあえず実際に使うことが出来るのか見るために、上記の幽霊型の例をFlowtypeに落とし込みます。

```js
class A<T> {
    x: number;
    constructor(x: number) {
        this.x = x;
    }
}
var res0: A<string> = new A(3);
var res1: A<Array<string>> = new A(3);

var a: A<string> = res0;
var b: A<string> = res1; // Error
```

* http://tryflow.org/#eccc546a104c4bc364ce7413d249625e

上記のコードでFlowtypeでcheckすると

```js
var a: A<string> = res0;
```

では型が一致するのでcheckが通りますが、

```js
var b: A<string> = res1; // Error
```

では型が一致しないのでcheckでエラーが発生します。
実際には`A<T>`の`T`は使用していないので`A`型として動いてくれます。いい感じですね！！

とはいえ、これだけだとあまりおもしろさが分からないので、もう少しJSで使えそうな実用例で遊んでみます。

# JSでの実用例（理想）

JSでイベントを扱うときにイベント名に対して、コールバックで受け取る引数は大抵決まっています。
しかし、この手の型指定は大抵でイベント名を`string`、コールバックを`Function`として引数の型チェックをしないことが多いです。

これだとせっかく型を扱うのに静的にチェックできないとか意味がないよね・・・ということでPhantom Typeでイベント名に対応した引数をチェックできるようにします。

```js
type Event = { type: string; };
type EventType<T> = "Event";

class EventEmitter {
    on<A, E: EventType<A>>(name: E, listener:(event: A) => void): EventEmitter {
        // ...
        return this;
    }
}

var type: EventType<Event> = "Event";

var e = new EventEmitter();
e.on(type, (event) => {
    console.log(event.type);
    console.log(event.hoge); // Error!!
});
```

* http://tryflow.org/#97c871a4112da8323528fb37d6c34bbe

できました。

Flowtypeでは

```js
type Hoge = "Hoge";

var str1: Hoge = "Hoge";
var str2: Hoge = "Fuga"; // Error!!
```

* http://tryflow.org/#d0207976d552324e68fd7529f0402a57

という感じに文字列リテラルを制限する型（何て言うんだろ？）を作れるので、これにPhantom Typeで型を付与してコールバックの引数に渡す型を定義できるようにします。

```js
type EventType<T> = "Event";
```

これに`on`で受け取って、コールバックの引数に`EventType<T>`の`T`を渡せるように定義します。

```js
on<A, E: EventType<A>>(name: E, listener:(event: A) => void): EventEmitter
```

これでイベント名に対応するコールバックの引数を定義できるようになります。Phantom Type最高ですね！！！


と、言いたいところですが、このコードはFlowtypeで想定通りに動きません・・・。
どうやら`type`を使ってPhantom Typeを行おうとすると型が`any`に落とされてしまうようで、

```js
console.log(event.hoge); // Error!!
```

でエラーが発生してくれないようです。
実際にエラーを出すには

```js
type Event = { type: string; };
type EventType<T> = "Event";

class EventEmitter {
    on<A, E: EventType<A>>(name: E, listener:(event: A) => void): EventEmitter {
        // ...
        return this;
    }
}

var type: EventType<Event> = "Event";

var e = new EventEmitter();
e.on(type, (event: Event) => {
    console.log(event.type);
    console.log(event.hoge); // Error!!
});
```

* http://tryflow.org/#e818996726e9536b7af428b8c41dba27

とコールバックの引数に型を指定してやる必要があります。
何というかPhantom Typeを使う意味が全くありませんね！！！！

`class`を使えば`any`にならずに想定した通りに動くので、その形に変更します。

# JSでの実用例（現実）

```js
type Event = { type: string; };
class EventType<T> { };

class EventEmitter {
    on<A, E: EventType<A>>(name: Class<E>, listener:(event: A) => void): EventEmitter {
        // ...
        return this;
    }
}

var type: Class<EventType<Event>> = EventType;

var e = new EventEmitter();
e.on(type, (event) => {
    console.log(event.type);
    console.log(event.hoge); // Error!!
});
```

* http://tryflow.org/#465d9f8379340aea779c4594f2d2f419

できました。

イベント名にクラスを指定する形になったので、実際に実用するにはnodeの`EventEmitter`などをラップして`EventType`を文字列に落とす仕組みが必要になってきます。
とはいえ、これでイベント名に対応するコールバックの引数を静的にチェックをすることができるようになりました。Phantom Type最高ですね！！！

# おわりに

ひさしぶりにFlowtypeを触りましたが出来ることが本当に多くなりましたね。
今回は使用しませんでしたが、FlowtypeではコメントでFlowtype用のコードを書けるため、通常の静的型言語ではできない、型のためのコードと実際に動くコードを分けたりすることも出来たりします。
なかなか表現としておもしろいので皆さんもFlowtypeで楽しんでみてください。