tslint-to-eslint-configでtslint.jsonをeslintrcに変換する

# TL;DR
- TSLintは2019年内に開発終了なのでtypescript-eslintへの移行が必要
- [typescript-eslint/tslint-to-eslint-config](https://github.com/typescript-eslint/tslint-to-eslint-config)はtslint.jsonをeslintrcに変換してくれるツール
- その他のtypescript-eslintの設定については「[@typescript-eslint ことはじめ - teppeis blog](https://teppeis.hatenablog.com/entry/2019/02/typescript-eslint)」などを読んでください

# はじめに  
TSLintは公式でdeprecateになり2019年内に開発を終了することが決まっています。
参考: [Roadmap: TSLint -> ESLint · Issue #4534 · palantir/tslint · GitHub](https://github.com/palantir/tslint/issues/4534)

これからはTypeScriptでもESLintを使うことが推奨されています。TypeScriptチームがESLintチームと協力して[typescript-eslint](https://github.com/typescript-eslint/typescript-eslint)プロジェクトを始めました。
参考: [TypeScript on ESLint の未来 - Qiita](https://qiita.com/mysticatea/items/aaf677928e965abe093d)

TSLintからESLintに移行する際にtslint.jsonからeslintrcへの書き換えを行う必要がありますが、その書き換えを自動で行ってくれるコマンドラインツール[tslint-to-eslint-config](https://github.com/typescript-eslint/tslint-to-eslint-config)を紹介します。

# tslint-to-eslint-config

- [GitHub - typescript-eslint/tslint-to-eslint-config: Converts your TSLint configuration to the closest possible ESLint equivalent.](https://github.com/typescript-eslint/tslint-to-eslint-config)

このツールは@typescript-eslintチームが開発しているツールです。
プロジェクト内にあるtslint.jsonの設定を読み取りeslintrcの設定をしてくれます。
tslint.jsonがあるディレクトリで以下のコマンドを実行します。

```bash
npx tslint-to-eslint-config
```

`eslintrc.js`と`tslint-to-eslint-config.log`が生成されます。

```bash
├── eslintrc.js // 生成されたファイル
├── index.ts
├── package.json
├── tsconfig.json
├── tslint-to-eslint-config.log // 生成されたファイル
└── tslint.json
```

元のtslint.jsonは以下のような設定だったとします。

```json
{
  "rules": {
    "adjacent-overload-signatures": true,
    "ban-comma-operator": true,
    "no-namespace": true,
    "no-parameter-reassignment": true,
    "no-reference": true,
    "no-unnecessary-type-assertion": true,
    "label-position": true,
    "no-conditional-assignment": true,
    "no-construct": true,
    "no-duplicate-super": true,
    "no-duplicate-switch-case": true,
    "no-duplicate-variable": [true, "check-parameters"],
    "no-shadowed-variable": true,
    "no-empty": [true, "allow-empty-catch"],
    "no-floating-promises": true,
    "no-implicit-dependencies": true,
    "no-invalid-this": true,
    "no-string-throw": true,
    "no-unsafe-finally": true,
    "no-void-expression": [true, "ignore-arrow-function-shorthand"],
    "no-duplicate-imports": true,
    "no-empty-interface": {"severity": "warning"},
    "no-import-side-effect": {"severity": "warning"},
    "no-var-keyword": {"severity": "warning"},
    "triple-equals": {"severity": "warning"},
    "deprecation": {"severity": "warning"},
    "prefer-for-of": {"severity": "warning"},
    "unified-signatures": {"severity": "warning"},
    "prefer-const": {"severity": "warning"},
    "trailing-comma": {"severity": "warning"}
  },

  "defaultSeverity": "error"
}
```

出力された`eslintrc.js`は以下です。

```js
module.exports = {
    "env": {
        "browser": true
    },
    "parser": "@typescript-eslint/parser",
    "parserOptions": {
        "project": "tsconfig.json",
        "sourceType": "module"
    },
    "plugins": [
        "@typescript-eslint",
        "@typescript-eslint/tslint"
    ],
    "rules": {
        "@typescript-eslint/adjacent-overload-signatures": "error",
        "@typescript-eslint/no-empty-interface": "warn",
        "@typescript-eslint/no-namespace": "error",
        "@typescript-eslint/no-param-reassign": "error",
        "@typescript-eslint/no-triple-slash-reference": "error",
        "@typescript-eslint/no-unnecessary-type-assertion": "error",
        "@typescript-eslint/prefer-for-of": "warn",
        "@typescript-eslint/unified-signatures": "warn",
        "constructor-super": "error",
        "no-cond-assign": "error",
        "no-duplicate-case": "error",
        "no-empty": [
            "error",
            {
                "allowEmptyCatch": true
            }
        ],
        "no-empty-functions": "error",
        "no-invalid-this": "error",
        "no-new-wrappers": "error",
        "no-sequences": "error",
        "no-throw-literal": "error",
        "no-unsafe-finally": "error",
        "no-unused-labels": "error",
        "no-var": "warn",
        "prefer-const": "warn",
        "@typescript-eslint/tslint/config": [
            "error",
            {
                "rules": {
                    "deprecation": true,
                    "no-duplicate-imports": true,
                    "no-duplicate-variable": [
                        true,
                        "check-parameters"
                    ],
                    "no-floating-promises": true,
                    "no-implicit-dependencies": true,
                    "no-import-side-effect": true,
                    "no-shadowed-variable": true,
                    "no-void-expression": [
                        true,
                        "ignore-arrow-function-shorthand"
                    ],
                    "trailing-comma": true,
                    "triple-equals": true
                }
            }
        ]
    }
};
```

ESLint本体に無いルールは`@typescript-eslint/xxx`で設定されます。このルールを適用している状態で実行するには`@typescript-eslint/eslint-plugin`や`@typescript-eslint/eslint-plugin-tslint`といったプラグインをインストールする必要があります。

```
npm install --save-dev @typescript-eslint/eslint-plugin @typescript-eslint/eslint-plugin-tslint
```

生成されたもう1つのファイル`tslint-to-eslint-config.log`には変換時のログを出力します。今回の場合は以下のログが出力され、deprecationのルールを使っていることを示してくれています。

```txt
deprecation does not yet have an ESLint equivalent.
no-duplicate-imports does not yet have an ESLint equivalent.
no-duplicate-variable does not yet have an ESLint equivalent.
no-floating-promises does not yet have an ESLint equivalent.
no-implicit-dependencies does not yet have an ESLint equivalent.
no-import-side-effect does not yet have an ESLint equivalent.
no-shadowed-variable does not yet have an ESLint equivalent.
no-void-expression does not yet have an ESLint equivalent.
trailing-comma does not yet have an ESLint equivalent.
triple-equals does not yet have an ESLint equivalent.
```

# Flags

## ファイル名指定
tslint-to-eslint-configには実行時にフラグをつけることでファイル名の指定などができます。

例えば、何らかの理由でtslint.jsonの名前を変更している場合があるとします。

```bash
├── index.ts
├── package.json
├── tsconfig.json
├── tslint.front.json
└── tslint.server.json
```

上記のような場合は、`--tslint`オプションを使うことで読み込むtslintの設定ファイルを指定することができます。また、`--config`オプションを使うことで出力するファイル名を変更することもできます。

```bash
npx tslint-to-eslint-config --tslint ./tslint.front.json --config eslintrc.front.js
```

上記では直下にある`tslint.front.json`を読み込み、`eslintrc.front.js`という名前で出力しています。

```bash
npx tslint-to-eslint-config --tslint ./tslint.server.json --config eslintrc.server.js
```

上記では直下にある`tslint.server.json`を読み込み、`eslintrc.server.js`という名前で出力しています。

## JSON出力

デフォルトでは`eslintrc`はJavaScriptのモジュールとして出力されますが、`--config`オプションを使うことでJSONで出力することもできます。

```bash
npx tslint-to-eslint-config --config .eslintrc.json
```

他にも便利なpackage.jsonの依存を読み込む`--package`オプションなどあるので、興味のある方は[READMEのこちら](https://github.com/typescript-eslint/tslint-to-eslint-config#cli-flags)を参考にしてみてください。

# eslint実行時の注意

### @typescript-eslint/tslintが必要な場合
前述のとおり生成された`eslintrc`の`plugins`に`@typescript-eslint/tslint`が指定されている場合は、[@typescript-eslint/eslint-plugin-tslint](https://www.npmjs.com/package/@typescript-eslint/eslint-plugin-tslint)のインストールが必要です。

### ルールが見つからない場合
実行時に以下のようなエラーが出力されることがあります。

```
Definition for rule '@typescript-eslint/no-param-reassign' was not found 
```

このようにルールが見つからなくてエラーが出る場合は手動で`eslintrc`のルールをコメントアウトしたりESLintのルールに書き換える必要があります。
上記のエラーの場合だとESLintに[no-param-reassign](https://eslint.org/docs/rules/no-param-reassign)ルールが存在するので書き換えてあげると良いでしょう。

# 最後に
TSLintをまだお使いの方は今回紹介したtslint-to-eslint-configを使ってESLintへ移行してください。TSLintは2019年内に開発が終了する予定です。また、他にもtypescript-eslint関連で便利なツールがあればコメント欄などや[Twitter(@shisama_)](https://twitter.com/shisama_)などで教えていただけると幸いです。
今回紹介した内容は[GitHub(shisama/tslint-to-eslint-sample)](https://github.com/shisama/tslint-to-eslint-sample)にあるのでご興味あればご覧いただけると幸いです。

最後までお読みいただきありがとうございました。