TypeScript と Babel を両方使って ES6 を書く

# Motivation
* TypeScript 大好き！型万歳！
* ES6 も書いてみたいので、 Babel も使いたい
* `tsc --target es6 && babel` すれば両方使えるっぽい
* でもそれってどのくらい実用的なの？

ということで、`tsc --target es6 && babel` がどのくらい使えるものなのか実験してみました。

# 手順
1. TypeScript は 1.5.0-beta のリリースからだいぶ日が経っており、これで実験するのもアレなので、とりあえず master の最新を持ってくる。
2. Babel のサイトに載っている、 [ES6 のサンプルコード](https://babeljs.io/docs/learn-es2015)を一通り写経して TypeScript 化する。
3. `tsc --target es6 && babel` してみる

実験に使用したコードはこちらです。

* https://github.com/kimamula/ts-babel

※注意1: コンパイル/トランスパイルが通るかどうかを調べただけで、期待通りに挙動するかどうかまでは確認していません。
※注意2: そもそも、 Proxy に関しては、 [Babel がはっきり "Unsupported" と言っている](https://babeljs.io/docs/learn-es2015/#proxies)ので、残念ながら動きません。

# 結果
使用したサンプルコードのうち、以下で tsc のコンパイルエラーが出ました。

## Module loaders
こんなコードです。

```ts
// Dynamic loading – ‘System’ is default loader
System.import("lib/math").then(function(m: {sum: (a: number, b: number) => number, pi: number}) {
  alert("2π = " + m.sum(m.pi, m.pi));
});

// Create execution sandboxes – new Loaders
var loader = new Loader({
  global: fixup(window) // replace ‘console.log’
});
loader.eval("console.log(\"hello world!\");");

// Directly manipulate module cache
System.get("jquery");
System.set("jquery", Module({$: window['$']})); // WARNING: not yet finalized
```

`System`, `Loader`, `Module`, `fixup` がないと言って怒られました (`fixup` は自前で用意すべき関数だったかも。。。)。
型定義ファイルを追加してあげればコンパイルは通りそうですが、そもそも `System` とか `Loader` って [ES6 の仕様](http://www.ecma-international.org/ecma-262/6.0/index.html)には見当たらず、どうも一度仕様に入ったがその後除かれて今は pending になっているそうです。

ということで、「 ES6 を書く」ことを目標とするならば、これはいったん忘れてもいいかもしれません。
（忘れたくない人は型定義ファイルを書きましょう）

## Spread operator
```ts
function fSpread(x: number, y: number, z: number) {
  return x + y + z;
}
// Pass each elem of array as argument
fSpread(...[1, 2, 3]) === 6;
```

コンパイルエラーにはなるのですが、 TypeScript 側ではすでに対応済みな痕跡があります。

* https://github.com/Microsoft/TypeScript/pull/1931

どうも↑を見ると、 TypeScript 的には以下のように書いてほしいようです。

```ts
function fSpread(...numArray: number[]) {
  return numArray[0] + numArray[1] + numArray[2];
}
// Pass each elem of array as argument
fSpread(...[1, 2, 3]) === 6;
```

実際、最初に書いたような書き方を許容してしまうと、 fSpread が (ひいてはあらゆる関数が) any[] を引数に取れるようになってしまいそうで、それはむしろやめてほしいよね、となんだか自分の中で納得しました。

ちなみに、どうしても最初の書き方をしたいときは、次のように書けばコンパイラーに見逃してもらえます。

```ts
(<any>fSpread)(...[1, 2, 3]) === 6;
```

## `__proto__` に指定したオブジェクトの `super` による参照
```ts
var obj = {
    // __proto__
    __proto__: new MyClass(10, 'Luke'),
    // Methods
    toString() {
     // Super calls
     return "d " + super.toString();
    }
};

```

`super.toString()` のところで、 `'super' can only be referenced in a derived class.` と言われました。

しかし、本当にこれが ES6 的に正しい構文なのかどうか、 [ES6 の仕様](http://www.ecma-international.org/ecma-262/6.0/index.html)を読んでもさっぱり判断できず。。

Babel と TypeScript の見解の相違という可能性もあるのではないかと。(ちなみに Chrome の Developer tool で試してみたら、 `__proto__` に指定したオブジェクトを `super` で参照できました)

仮に正しい構文だったとしても、普通は使わないだろうなあと思います。
フレームワーク書くときとかに便利だったりするかもしれませんが。

## String.prototype.includes
```ts
"abcde".includes("cd");
```

ES6 で String.prototype に追加されたのは、他にも `startsWith`, `endsWith`, `repeat` があり、それらはすべてコンパイルが通るのに、なんと `includes` だけ通りません。

「こいつ、誘ってるな」と思いましたね、正直な話。

というわけで、ここは遠慮なく誘いに乗る形で、 PR を作ってみました。 (すでに issue はあった)

* https://github.com/Microsoft/TypeScript/pull/3923

マージしてもらえるといいな。 -> してもらえました。わーい。

# まとめ
`String.prototype.includes` の件は残念でしたが、 Babel のサイトに載っているその他の ES6 のコードは、おおむね問題なく `tsc --target es6 && babel` できることが分かりました。

これで、臆することなく TypeScript と Babel を両方使って ES6 を書けそうです。

# その他
一応、 TypeScript 単体での ES6 対応がどのくらいのものか見るために、サンプルコードに対して `tsc --target es5` するのも試してみましたが、大量にエラーが出てしまいました。

下記によれば型関連のエラーは、明示的に ./node_modules/typescript/bin/lib.es6.d.ts を参照することで解決するようですが、シンタックスのエラーもあるので、やはり `tsc --target es6 && babel` のほうが ES6 のカバー範囲は増えそうです。

* [TypeScript 1.5 + ES6 を今すぐ使う方法を調べた](http://qiita.com/seanchas_t/items/06e0b859c09953d49845)