Motivation
- TypeScript 大好き!型万歳!
- ES6 も書いてみたいので、 Babel も使いたい
-
tsc --target es6 && babel
すれば両方使えるっぽい - でもそれってどのくらい実用的なの?
ということで、tsc --target es6 && babel
がどのくらい使えるものなのか実験してみました。
手順
- TypeScript は 1.5.0-beta のリリースからだいぶ日が経っており、これで実験するのもアレなので、とりあえず master の最新を持ってくる。
- Babel のサイトに載っている、 ES6 のサンプルコードを一通り写経して TypeScript 化する。
-
tsc --target es6 && babel
してみる
実験に使用したコードはこちらです。
※注意1: コンパイル/トランスパイルが通るかどうかを調べただけで、期待通りに挙動するかどうかまでは確認していません。
※注意2: そもそも、 Proxy に関しては、 Babel がはっきり "Unsupported" と言っているので、残念ながら動きません。
結果
使用したサンプルコードのうち、以下で tsc のコンパイルエラーが出ました。
Module loaders
こんなコードです。
// 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 の仕様には見当たらず、どうも一度仕様に入ったがその後除かれて今は pending になっているそうです。
ということで、「 ES6 を書く」ことを目標とするならば、これはいったん忘れてもいいかもしれません。
(忘れたくない人は型定義ファイルを書きましょう)
Spread operator
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 側ではすでに対応済みな痕跡があります。
どうも↑を見ると、 TypeScript 的には以下のように書いてほしいようです。
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[] を引数に取れるようになってしまいそうで、それはむしろやめてほしいよね、となんだか自分の中で納得しました。
ちなみに、どうしても最初の書き方をしたいときは、次のように書けばコンパイラーに見逃してもらえます。
(<any>fSpread)(...[1, 2, 3]) === 6;
__proto__
に指定したオブジェクトの super
による参照
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 の仕様を読んでもさっぱり判断できず。。
Babel と TypeScript の見解の相違という可能性もあるのではないかと。(ちなみに Chrome の Developer tool で試してみたら、 __proto__
に指定したオブジェクトを super
で参照できました)
仮に正しい構文だったとしても、普通は使わないだろうなあと思います。
フレームワーク書くときとかに便利だったりするかもしれませんが。
String.prototype.includes
"abcde".includes("cd");
ES6 で String.prototype に追加されたのは、他にも startsWith
, endsWith
, repeat
があり、それらはすべてコンパイルが通るのに、なんと includes
だけ通りません。
「こいつ、誘ってるな」と思いましたね、正直な話。
というわけで、ここは遠慮なく誘いに乗る形で、 PR を作ってみました。 (すでに issue はあった)
マージしてもらえるといいな。 -> してもらえました。わーい。
まとめ
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 のカバー範囲は増えそうです。