Babel7でTypeScriptをパースする

「ES6 + SCSS環境を作っとく」という記事を書きながら環境構築していたら、 Babelのバージョンが7.0.0になっていた。 ついに正式リリース、なんとなく聞いてはいたけど、すっかり忘れてた…。 とりあえずTypeScriptのパースを試してみた。

  • Node 8.8.1
  • yarn 1.2.1
  • tsc 1.5.3

での動作を確認。

ほとんどMicrosoftのブログをなぞっているだけな気がした。

インストール

今度から「@babel/なんちゃら」という形式になる。

yarn init
yarn add @babel/core @babel/cli typescript @babel/preset-typescript @babel/preset-env @babel/plugin-proposal-class-properties @babel/plugin-proposal-object-rest-spread -D

.babelrc.jsの作成

本アップデートにより".babelrc"だけでなく".babelrc.js"というのも作成できるようになった。
よくわからないけど試しにやった。

.babelrc.js
module.exports = {
    "presets": [
        "@babel/env",
        "@babel/typescript"
    ],
    "plugins": [
        "@babel/proposal-class-properties",
        "@babel/proposal-object-rest-spread"
    ]
}

tsconfig.jsonを作成

Babelはあくまでパースするだけなので、型チェックはtscで行う。
tscから出力する必要がないので、noEmitをtrueにする。

{
  "compilerOptions": {
    "allowJs": true,
    "allowSyntheticDefaultImports": true,
    "module": "esnext",
    "moduleResolution": "node",
    "noEmit": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "pretty": true,
    "skipLibCheck": true
  },
  "include": [
    "src"
  ]
}

packages.jsonの編集

パース用のbuildコマンドと型チェックのコマンドを追加する。

{
  "name": "babelts",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "devDependencies": {
    "@babel/cli": "^7.0.0",
    "@babel/core": "^7.0.0",
    "@babel/plugin-proposal-class-properties": "^7.0.0",
    "@babel/plugin-proposal-object-rest-spread": "^7.0.0",
    "@babel/preset-env": "^7.0.0",
    "@babel/preset-typescript": "^7.0.0",
    "typescript": "^3.0.1"
  },
  "scripts": {
    "build": "babel ./src --out-dir dist --extensions '.ts,.tsx'",
    "test": "tsc -w"
  }
}

書く

srcフォルダを作成し、中に"index.ts"を作成。

class Message {
  constructor(private text: string, private timestamp: number) {
    this.text = text
    this.timestamp = timestamp
  }
  public getText() {
    return this.text
  }
  public getTimeStamp() {
    return this.timestamp
  }
}

const message = new Message("こんにちは", 20180830)
console.log(message.getText(), message.getTimeStamp())

型チェック

yarn testを実行。

yarn test

エラーなかった。

> File change detected. Starting incremental compilation...
> Found 0 errors. Watching for file changes.

起動しながら、new Message()内の引数を入れ替えたりして確認した。

> src/index.ts:14:29 - error TS2345: Argument of type '20180830' is not assignable to parameter of type 'string'.
> 14 const message = new Message(20180830, "こんにちは");

出力

まずtscでコンパイルしてみる。

tsc src/index.ts
src/index.js
var Message = (function () {
  function Message(text, timestamp) {
    this.text = text;
    this.timestamp = timestamp;
    this.text = text;
    this.timestamp = timestamp;
  }
  Message.prototype.getText = function () {
    return this.text;
  };
  Message.prototype.getTimeStamp = function () {
    return this.timestamp;
  };
  return Message;
})();
var message = new Message("こんにちは", 20180830);
console.log(message.getText(), message.getTimeStamp());

次はyarn buildで、@babel/envと@babel/typescriptを通して出力。

yarn build
src/index.js
"use strict";

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }

var Message =
/*#__PURE__*/
function () {
  function Message(text, timestamp) {
    _classCallCheck(this, Message);

    this.text = text;
    this.timestamp = timestamp;
  }

  _createClass(Message, [{
    key: "getText",
    value: function getText() {
      return this.text;
    }
  }, {
    key: "getTimeStamp",
    value: function getTimeStamp() {
      return this.timestamp;
    }
  }]);

  return Message;
}();

var message = new Message("こんにちは", 20180830);
console.log(message.getText(), message.getTimeStamp());

できた。

namespace、enumのマージ(const enum?)、JSXでの"<any> foo"みたいな古い型アサーション、import foo = require()などには対応していない。

Babel7の他のアップデート内容はこちら。
Babel 7 Released