TypeScript + TSLint + Prettier + Webpack環境を作成したときのメモ

`TypeScript`は以前からちょくちょく触っていましたが、この度本格的に学習を始めたので、設定周りのメモを残しておきます。

`TypeScript`で`React`を書き、`TSLint` + `Prettier`をかけつつ`Webpack`でバンドルしたときの設定です。

各バージョンは以下のとおりです。

||バージョン|
|---|---|
|TypeScript|2.8.3|
|Webpack|4.8.1|
|TSLint|5.10.0|
|Prettier|1.12.1|


## TypeScript

babelでいう`.babelrc`であるところの`tsconfig.json`で、コンパイルオプションを指定できます。

使っているTypeScriptのバージョンは`2.8.3`ですが、以下の記事がとても参考になりました。
[tsconfig.json で指定できる全 compilerOptions をまとめた (TypeScript v2.5 版)](http://neos21.hatenablog.com/entry/2017/10/24/080000)

最終的に、`tsconfig.json`は以下のように設定しました。

```json:tsconfig.json
{
  "compilerOptions": {
    "outDir": "./public/",
    "module": "commonjs",
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "allowUnreachableCode": false,
    "allowUnusedLabels": false,
    "removeComments": true,
    "sourceMap": true,
    "target": "es5",
    "jsx": "react",
    "lib": [
      "es5",
      "es6",
      "dom"
    ]
  },
  "files": [
    "@types/images.d.ts"
  ],
  "include": [
    "./src/**/*"
  ],
  "exclude": [
    "node_modules"
  ]
}
```

せっかくのTypeScriptなので、恩恵を受けるためにも基本的に厳しめのルールを設定しています。

また、TS内で画像をimportしてWebpackでバンドルするために、独自の`d.ts`ファイルを定義しています。

```typescript:@types/images.d.ts
declare module '*.png'
```

これを読み込むため、`tsconfig.json`の`files`プロパティでファイルを指定しています。



## TSLint + Prettier

Lintには[TSLint](https://palantir.github.io/tslint/)を使い、フォーマッタとして[Prettier](https://prettier.io/)を併用します。
`tslint.json`に設定を記述していきます。

[JavaScript Standard Style](https://standardjs.com/)を採用するため、[tslint-config-standard](https://www.npmjs.com/package/tslint-config-standard)を使用します。
また、Prettierと連携するために[tslint-plugin-prettier](https://www.npmjs.com/package/tslint-plugin-prettier)を、TSLintとPrettierのルール衝突を避ける(Prettierのルールを優先させる)ために[tslint-config-prettier](https://www.npmjs.com/package/tslint-config-prettier)を使います。

```json:tslint.json
{
  "rulesDirectory": [
    "tslint-plugin-prettier"
  ],
  "extends": [
    "tslint-config-standard",
    "tslint-config-prettier"
  ],
  "rules": {
    "prettier": [
      true,
      {
        "singleQuote": true,
        "semi": false
      }
    ]
  }
}
```

[README](https://github.com/alexjoverm/tslint-config-prettier/blob/master/README.md)にも書いてますが、`tslint-config-prettier`は`extends`プロパティの**末尾**に入れます。
個別に設定したいルールは、`rules`プロパティに記述します。
Prettierのデフォルトでは、文字列リテラルはダブルクォーテーション使用、文末にセミコロンを記述する設定になっているので、それぞれ上書きしています。


## Webpack

TypeScript-Webpack連携に[awesome-typescript-loader](https://www.npmjs.com/package/awesome-typescript-loader)、TSLint-Webpack連携に[tslint-loader](https://www.npmjs.com/package/tslint-loader)を使います。

```javascript:webpack.config.js
const webpack = require('webpack');
const path = require('path');

module.exports = {
  mode: 'development',
  devtool: 'inline-source-map',
  entry: {
    bundle: path.join(__dirname, '../../src/typescript/index.tsx'),
  },
  output: {
    path: path.join(__dirname, '../../public'),
    filename: '[name].js',
  },
  module: {
    rules: [
      {
        enforce: 'pre',
        test: /\.tsx?$/,
        use: [
          {
            loader: 'tslint-loader',
            options: {
              typeCheck: true,
              fix: true,
            },
          },
        ],
      },
      {
        test: /\.tsx?$/,
        exclude: /node_modules/,
        use: 'awesome-typescript-loader',
      },
      {
        enforce: 'pre',
        test: /\.js$/,
        use: 'source-map-loader',
      },
      {
        test: /\.(jpg|png)$/,
        use: 'url-loader',
      },
    ]
  },
  resolve: {
    extensions: ['.ts', '.tsx', '.js']
  },
  devServer: {
    host: 'localhost',
    port: 9000,
    contentBase: path.join(__dirname, '../../public'),
  },
};
```

`tslint-loader`のオプションで`fix: true`とすることで、lint時に自動修正してくれます。
また、`typeCheck: true`としておかないと、`tslint-config-standard`使用時に以下のようなWarningが表示されます。

```
Warning: The 'await-promise' rule requires type information.
Warning: The 'no-unused-variable' rule requires type information.
Warning: The 'no-use-before-declare' rule requires type information.
Warning: The 'return-undefined' rule requires type information.
Warning: The 'no-floating-promises' rule requires type information.
Warning: The 'no-unnecessary-qualifier' rule requires type information.
Warning: The 'no-unnecessary-type-assertion' rule requires type information.
Warning: The 'strict-type-predicates' rule requires type information.
```

ただ、TSLint本家のtype check機能はdeprecatedなので、この辺りはまた変更されるかもしれません。


## 雑感

* やはり型があると些細なミスに気付けて安心感がある
* 上記設定でwatchしてるときにVimでコード書いてると、保存時に裏でtslintのfixが走って再読込しないといけないのでちょっと面倒
    * lint+フォーマットはWebpackに含めず、別のnpm scriptsにして任意のタイミングで走らせた方がやりやすいかも？