LoginSignup
26

More than 5 years have passed since last update.

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

Last updated at Posted at 2015-07-18

Motivation

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

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

手順

  1. TypeScript は 1.5.0-beta のリリースからだいぶ日が経っており、これで実験するのもアレなので、とりあえず master の最新を持ってくる。
  2. Babel のサイトに載っている、 ES6 のサンプルコードを一通り写経して TypeScript 化する。
  3. 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 のカバー範囲は増えそうです。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26