JavaScript
TypeScript
webpack
ESLint
babel

Babel 7でTypeScriptをトランスパイルしつつ型チェックをする 〜webpack 4 + Babel 7 + TypeScript + TypeScript EsLint + Prettierの開発環境を構築する〜


はじめに

表題の通りですが、Babel 7でTypeScriptをトランスパイルをするための、webpack 4 + Babel 7 + TypeScript + TypeScript ESLint + Prettierの開発環境構築に関しての備忘録です。

記事本文に記載している開発環境はGitHubに置いてあります。

hira777/webpack-babel7-with-typescript

webpackやPrettierなどを理解していることを前提とした記事ですので、基礎知識を習得したい方は以下の記事をご覧ください。


開発環境の特徴


  • Babel(webpackのbabel-loader)でTypeScriptをトランスパイルする。そのため、ts-loaderは利用しない。

  • Babelでは型チェックはできないため、型チェックはTypeScript(tsc)でする。

  • 構文チェックにはTSLintではなく、TypeScript ESLintを利用する。

  • TypeScript ESLintをPrettierと併用して、コード整形もできるようにする。

Babel 7からTypeScriptのトランスパイルが可能になりました。少し前にJestがバージョンアップし、TypeScriptをサポートしましたが、それも BabelでTypeScriptをトランスパイルすることで実現しています

しかし、型チェックはできないため、型チェックのためにTypeScriptが必要になります(Jestも同様で、テスト実行時に型チェックをするためにはts-jestが必要です)。また、ネームスペースなどの一部の TypeScipt 構文はトランスパイルできないです

そして、TypeScript ESLintのversion1.x系もリリースされているので、それらを取り入れてみた開発環境になります。


そもそもBabelでTypeScriptをトランスパイルする意味はあるのか?

以下のような理由でBabelのエコシステム上でTypeScriptのコードを扱いたい状況でなければ、TypeScript単体の利用で良く、無理に併用する必要はないと思っています。


  • Babelを利用したビルド環境がすでに存在し、環境を一から構築することはできないがTypeScriptを利用したい。

  • 開発、もしくは利用しているライブラリなどが特定のBabelプラグインに依存している。

  • 何らかの理由で、TypeScriptでトランスパイルしたJavaScriptをBabelでトランスパイルしており、トランスパイルをBabelだけで済むようにしたい。

また、以下の記事のようにBabelからTypeScriptに移行する手段もあるため、本記事のようなBabelとの併用はあくまで手段の1つとして認識していただければ良いと思います。


ディレクトリ構成

本記事での開発環境のディレクトリ構成は以下を前提とする(.babelrc.eslintrcなどの設定ファイルの詳細は後述)。

.

├── .babelrc
├── .eslintrc
├── package.json
├── public
│ └── bundle.js
├── src
│ ├── app.ts
│ └── modules
│ └── add.ts
├── tsconfig.json
└── webpack.config.js


package.json

パッケージをローカルインストールするため、package.jsonは以下のコマンドで生成しておく。

npm init -y

# もしくは
# yarn init


app.ts(エントリーポイント)


src/app.ts

import add from './modules/add';

console.log(add(10, 5));



add.ts


src/modules/add.ts

export default function add(number1: number, number2: number): number {

return number1 + number2;
}


開発環境のセットアップ


  • Babelのセットアップ

  • webpackのセットアップ

  • TypeScriptのセットアップ

  • TypeScript ESLintとPrettierのセットアップ


Babelのセットアップ

ますはBabelを利用するために最低限必要なパッケージをインストールする。

npm i @babel/core @babel/preset-env -D

# もしくは
# yarn add @babel/core @babel/preset-env -D

BabelでTypeScriptをトランスパイルするためには以下のパッケージも必要なのでインストールする。

npm i @babel/plugin-proposal-class-properties @babel/plugin-proposal-object-rest-spread @babel/preset-typescript -D

# もしくは
# yarn add @babel/plugin-proposal-class-properties @babel/plugin-proposal-object-rest-spread @babel/preset-typescript -D


.babelrcの設定

上記でインストールしたパッケージ(プリセットとプラグイン)を利用するため、設定は以下のようになる。


.babelrc

{

"presets": ["@babel/env", "@babel/typescript"],
"plugins": ["@babel/proposal-class-properties", "@babel/proposal-object-rest-spread"]
}


webpackのセットアップ

webpackを利用するために必要なパッケージをインストールする。前述の通りts-loaderはインストールしない。

npm i webpack webpack-cli babel-loader -D

# もしくは
# yarn add webpack webpack-cli babel-loader -D


webpack.config.jsの設定

BabelでTypeScriptをトランスパイルするため、以下のように拡張子が.tsのファイルに対してbabel-loaderを実行するように設定する。


webpack.config.js

const { resolve } = require('path');

module.exports = {
// エントリーポイントの設定
entry: './src/app.ts',
// 出力の設定
output: {
// 出力するファイル名
filename: 'bundle.js',
// 出力先のパス(絶対パスを指定する必要がある)
path: resolve(__dirname, 'public')
},
resolve: {
extensions: ['.ts']
},
module: {
rules: [
{
// ローダーの処理対象ファイル
test: /\.ts$/,
// 利用するローダー
use: 'babel-loader',
// ローダーの処理対象から外すディレクトリ
exclude: /node_modules/
}
]
}
};



TypeScriptのセットアップ

型チェックを行うためにTypeScriptをインストールする。

npm i typescript -D

# もしくは
# yarn add typescript -D


tsconfig.jsonの設定

includeは開発環境に応じて変更。


tsconfig.json

{

"compilerOptions": {
/* トランスパイル後のECMAScriptのバージョン */
"target": "esnext",

/* 相対パスではないモジュールは node_modules 配下を検索する */
"moduleResolution": "node",

/* 今回、トランスパイルは Babelが行うので、`tsc`コマンドでJavaScriptファイルを出力しないようにする */
"noEmit": true,

/* 厳格な型チェックオプション(noImplicitAny、noImplicitThis、alwaysStrict、
strictBindCallApply、strictNullChecks、strictFunctionTypes、
strictPropertyInitialization)を有効化する */
"strict": true,

/* 各ファイルを個々のモジュールとしてトランスパイルする。
Babel では技術的制約で、ネームスペースなどのファイルを跨いだ構文を解釈してトランスパイルできない。
このオプションを有効にすれば、Babel でトランスパイルできない TypeScriptの構文を検出して警告を出す */
"isolatedModules": true,

/* ES modules 形式以外の、CommonJS 形式などのモジュールを default import 形式で読み込める
例)const module = require('module') -> import module from 'module' */
"esModuleInterop": true
},
"include": ["src/**/*"]
}



TypeScript ESLintとPrettierのセットアップ

TypeScript ESLintを利用するために必要なパッケージをインストールする。

npm i eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin -D

# もしくは
# yarn add @typescript-eslint/parser @typescript-eslint/eslint-plugin -D

次に、PrettierとTypeScript ESLintを併用するために必要なパッケージをインストールする。

npm i prettier eslint-plugin-prettier eslint-config-prettier -D

# もしくは
# yarn add prettier eslint-plugin-prettier eslint-config-prettier -D


.eslintrcの設定

以下のようにprettier/@typescript-eslintを記述することで、plugin:@typescript-eslint/recommendedのコードフォーマット関連のルールが無効になり、Prettierとの競合を避けられる。


.eslintrc

{

"parser": "@typescript-eslint/parser",
"extends": [
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended",
"prettier/@typescript-eslint"
],
"rules": {
"prettier/prettier": [
"error",
{
"singleQuote": true
}
]
}
}


動作確認

上記のセットアップが完了すれば、


  • Babel(webpackのbabel-loader)でTypeScriptのトランスパイル

  • TypeScript(tsc)で型チェック

  • TypeScript ESLintとPrettierを併用した状態でESLintの実行

が可能になるので、それぞれの処理を実行していく。

それぞれの処理を実行するために、package.jsonに以下の記述を追加する。

  "scripts": {

"check-types": "tsc",
"dev": "webpack --mode development",
"lint": "eslint --fix --ext .ts ./src"
}


Babel(webpackのbabel-loader)でTypeScriptのトランスパイルをする

npm run dev

# もしくは
# yarn dev

# 以下のような実行結果が出力される。
Hash: 91172258ce54870de710
Version: webpack 4.29.6
Time: 740ms
Built at: 2019-04-08 21:39:45
Asset Size Chunks Chunk Names
bundle.js 4.83 KiB main [emitted] main
Entrypoint main = bundle.js
[./src/app.ts] 173 bytes {main} [built]
[./src/modules/add.ts] 92 bytes {main} [built]

Babel(webpackのbabel-loader)でTypeScriptファイル(app.tsadd.ts)をトランスパイルできた。


TypeScript(tsc)で型チェックをする

前述の通り、Babelは型チェックをしないため、以下のように変更をしてもトランスパイルできてしまう。

import add from './modules/add';

console.log(add(10, '5'));

TypeScript(tsc)で型チェックをする。

npm run check-types

# もしくは
# yarn check-types

# 以下のような実行結果が出力される。
src/app.ts:5:36 - error TS2345: Argument of type '"5"' is not assignable to parameter of type 'number'.

5 console.log(add(10, '5'));
~~~
Found 1 error.

型チェックできた。

監視したい場合はnpm run check-types -- --watchを実行する。


TypeScript ESLintとPrettierを併用した状態でESLintを実行する

npm run lint

# もしくは
# yarn lint

lint.gif

エラー出力とコード整形をできた。


終わり

本記事で記載した通り、BabelでTypeScriptのトランスパイルは簡単にできます。

状況によっては不要ですが、手段の1つとして覚えておくと役に立つかもしれません。


参考