【始め方】TypeScript プロジェクト開始時にやること(TypeScript + ESLint + Prettier + husky + lint-staged + ts-node + depcheck)

# 始めに
TypeScript, ESLint, Prettier, husky, lint-staged, ts-node を使用したプロジェクトを開始する時にやることについて書いていきます。

# 開始するために必要なものを揃える
## node
node のバージョン管理をするために、nodenv を入れます。
nodenv は [anyenv](https://github.com/anyenv/anyenv) で入れます。

```bash
# nodenv のインストール
anyenv install nodenv

# nodeのインストール
# 🚨 M1 Mac を使用している場合の注意点として、14 以下は使用できないようです。
nodenv install {{安定版で最新のもの}} # e.g. 16.7.0
```

## yarn
npm 経由で入れると各バージョン毎に入れないといけないので、brew で入れます。

```bash
brew install yarn
```

# プロジェクトの作成

## init
```bash
yarn init # 対話式で聞かれるので、入力して package.json を作成
```

## typescript 導入
```bash
# typescript, ts-node のインストール
yarn add -D typescript ts-node @types/node@"^16.7.0"

# tsconfig の作成
yarn run tsc --init
```

## ESLint, prettier の導入
```bash
# インストール
yarn add -D prettier eslint eslint-config-prettier

# eslint の初期設定
# 対話式で、入力していく
# Would you like to install them now with npm? は　Yes を選択
yarn run eslint --init

# npmではなくyarnを使ってるので、やり直し
rm -rf package-lock.json
yarn install
```

`@typescript-eslint/explicit-function-return-type` の rule を有効化する

```javascript:.eslintrc.js
rules: {
  "@typescript-eslint/explicit-function-return-type": "warn",
  ...
}
```

prettier に対応させるために、`.eslintrc.js` を修正して extends の**最後**に `"prettier"`を入れる

```js
extends: [... "prettier"],
```

prettier の設定ファイルの作成

```bash
echo "module.exports = {\n\tprintWidth: 120\n}" > .prettierrc.js
echo "tsconfig.json" > .prettierignore
```

## import 周りをいい感じにする
デフォルトでは import の並び順はチェックしてくれず、`eslint-plugin-import` が typescript に対応していないため、`unable to resolve path to module **`というエラーが出ます。

そのため、

https://github.com/alexgorbatchev/eslint-import-resolver-typescript

を使用することで対応します。

まずはプラグインをインストール

```bash
yarn add -D eslint-import-resolver-typescript
```

`tsconfig.json`を編集

```json:tsconfig.json
{
  ...
  "baseUrl": ".",  
  "paths": {
    "@/*": ["src/*"]
  },
  ...
}
```

こうすることで、以下のような構成の時、各ファイルからの相対パスではなく `src`を`@`としたパスで指定できるようになります
つまり、`main.ts` で `import { foo } from "@/hoge";` とimportできます

```
.
├── README.md
├── package.json
├── src
│   ├── main.ts
│   └── hoge.ts
├── tsconfig.json
└── yarn.lock
```



`eslint.js`を編集

```javascript
module.exports = {
  ...
  extends: [..., "plugin:import/recommended", "plugin:import/typescript", "prettier"],
  ...
  rules: {
    "import/order": [
      "error",
      {
        groups: ["builtin", "external", "parent", "sibling", "index", "object", "type"],
        // pathGroups: [
        //   {
        //     pattern: "@alias/**",
        //     group: "parent",
        //     position: "before",
        //   },
        // ],
        alphabetize: {
          order: "asc",
        },
        "newlines-between": "always",
      },
    ],
  },
  settings: {
    "import/resolver": {
      typescript: {
        // alwaysTryTypes: true, // always try to resolve types under `<root>@types` directory even it doesn't contain any source code, like `@types/unist`
        project: ".",
      },
    },
  },
};

```

`import/order` についてはこちらに記載されています

https://github.com/import-js/eslint-plugin-import/blob/master/docs/rules/order.md

vscode で自動で整形できるように設定を変更します

```json:settings.json
{
  ...
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  }
  ...
}
```


設定方法はこちらのサイトを参考にさせていただきました

https://buildersbox.corp-sansan.com/entry/2021/05/28/110000

以上の変更でエディタ上では完璧に動作するのですが、`ts-node`で実行するとエラーが発生してしまいます。
そこで`tsconfig-paths`というパッケージを使用して、問題を解消します

https://www.npmjs.com/package/tsconfig-paths

```bash
yarn add -D tsconfig-paths`
```

最後に、`package.json`の`scripts`を変更します

```diff:package.json
- "start": "ts-node main.ts",
+ "start": "ts-node -r tsconfig-paths/register ./src/main.ts",
```

## depcheck, husky, lint-staged の導入
https://github.com/depcheck/depcheck

https://typicode.github.io/husky/#/?id=automatic-recommended

huskyの追加 & 設定

```bash
npx husky-init && yarn # huskyがインストールされ、package.json に prepare が追加される
```

depcheck, lint-staged の追加

```bash
yarn add -D depcheck lint-staged
```

`package.json` に追記

```json:package.json
{
  "scripts": {...},
  "lint-staged": {
    "*.{js,jsx,ts,tsx,json,md}": [
      "prettier --write"
    ],
    "*.{js,jsx,ts,tsx}": [
      "eslint --fix"
    ]
  },
  "devDependencies": {...}
}

```

`.husky/pre-commit`を書き換える

```diff_shell
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

- npm test
+ yarn run depcheck
+ yarn run lint-staged
```

`.depcheckrc`を作成する

```bash
echo 'ignores: ["depcheck", "prettier", "tsconfig-paths"]' > .depcheckrc
```

## 実行ファイルの作成 & 実行
typescript のファイルを作成 (e.g. `main.ts`)

```typescript:main.ts
// eslint-disable-next-line no-console // こうしないと、eslint が通らず commit できない
console.log("Hello");

```

`package.json` にスクリプトを追加

```json
{
  "license": "MIT",
  "scripts": {
    "start": "ts-node main.ts", // これを追加
    "prepare": "husky install"
  },
  "lint-staged": {...},
}

```

実行

```bash
yarn start
# Hello
```

# おわりに
以上で、 TypeScript, ESLint, Prettier, husky, lint-staged, ts-node を使ったプロジェクトの雛形を作成することができました👏

# 参考
https://qiita.com/koinori/items/ed13ab8bbc6edcc5deb9

https://qiita.com/notakaos/items/3bbd2293e2ff286d9f49

https://qiita.com/soarflat/items/06377f3b96964964a65d

https://qiita.com/notakaos/items/3bbd2293e2ff286d9f49

https://typicode.github.io/husky/#/

https://buildersbox.corp-sansan.com/entry/2021/05/28/110000