【TypeScript】tsconfig.jsonの設定

# まえがき
TypeScriptを使う機会が多いので、設定ファイルであるtsconfig.jsonの中身を自分で設定できるよう本稿にまとめる。

https://www.typescriptlang.org/docs/handbook/tsconfig-json.html

https://typescriptbook.jp/reference/tsconfig/tsconfig.json-settings

https://t-cr.jp/memo/3bc17a18b9fac91f

# 前提整理
当たり前のことであるが改めてTypeScriptについて整理する。
## TypeScript実行方法
以下の2STEPで実行される。

STEP1　hoge.ts（TypeScript） → hoge.js（JavaScript） にコンパイル　【**npx tscコマンド**】
STEP2　hoge.js（JavaScript）実行

・Node.js環境では、JSファイルは`node`コマンドで実行できる。
・`npx tsc ---.ts`をしてから`node ---.js`を毎回実行するのは面倒なので、これを1コマンドにまとめた`ts-node`コマンドが存在する。

# tsconfig.jsonとは？
（`tsc`コマンドが「TS→JSにコンパイルするもの」を踏まえた上で）
・**TSファイルをJSファイルにコンパイルする**ための設定ファイル。
・`tsc`コマンド実行時にTSコンパイラは次の順番でtsconfig.jsonを探す。
　- the current directory
　- the parent direcotry chain
見つかったtsconfig.json内の設定情報をもとに、TSファイルのコンパイルを実行する。

# tsconfig.jsonの設定項目

## include

https://qiita.com/ryokkkke/items/390647a7c26933940470

コンパイル対象のものを定義する。

>拡張子を指定しない、もしくは拡張子にアスタリスクを使用する（hoge.*）場合、**デフォルトでは下記の拡張子のファイルのみが対象になる。**
・.ts
・.tsx
・.d.ts
ただし、compilerOptions.allowJsがtrueの場合は、下記の拡張子も含む。
・.js
・.jsx

## exclude

https://qiita.com/ryokkkke/items/390647a7c26933940470

コンパイル対象外のものを定義する。

>なので、例えば exclude に hoge.ts を指定しても、 include に含まれている piyo.ts が hoge.ts を import していれば tsc は hoge.ts を読み込みます。
下記ドキュメントをご確認ください。

>**excludeは指定しない場合デフォルトで以下の値を含む。**
・node_modules
・bower_components
・jspm_packages
・outDirオプションで指定しているディレクトリ配下のファイル
逆に言うと、tsconfig.jsonにexcludeオプションが指定されている場合は、outDirの中身も対象になってしまう。

## extends
自分で1からtsconfig.json設定するの面倒じゃない？ということで、baseとなるtsconfig.jsonがGitHubで公開されている。自分が用意したtsconfig.jsonにて、`extends`プロパティを定義することで参照できる。

https://github.com/tsconfig/bases/blob/main/bases

Node14環境でJavaScriptを実行する場合、下記のように設定できる。
```json
{
  "extends": "@tsconfig/node14/tsconfig.json",
  "compilerOptions": {
    "preserveConstEnums": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "**/*.spec.ts"]
}
```

## compilerOptions
|プロパティ名  |説明  |
|---|---|
|target  |出力するJavaScriptのバージョン指定。<br>[Node.jsのバージョン毎に推奨されるtargetがある。](https://zenn.dev/chida/articles/bdbcd59c90e2e1)<br>設定値（ES5, ES6/ES2015〜ES12/ES2021）  |
|lib  |・targetで指定したESモジュールに含まれない、けど使いたいライブラリをここで指定する。<br>・"組み込みライブラリ"という呼び方がしっくりくるかな。<br>・targetで指定しているJSのバージョンに含まれているものは暗黙的に指定されるが、改めて指定してもよい。<br>ブラウザ上で動かすJavaScriptなら`dom`を指定して`window, document`のような型情報を読み込む👍 ※[参考](https://www.typescriptlang.org/tsconfig#lib)|
|module  |出力されるJavaScriptが、どのようにモジュールを読み込むか指定する。<br>設定値<br>・commonjs：バックエンド(NodeJS)の場合<br>・esnext/es6：フロントエンド(JavaScript)の場合<br>[その他オプション](https://qiita.com/suin/items/3a73eb73eea51cfca9e1) |
|types  |デフォルトでは、すべての表示されている@typesパッケージがコンパイル時にインクルードされる。<br>typesを設定すると、リストに列挙したパッケージのみがインクルードされる。<br>```"types": ["node"```の場合、`./node_modules/@types/node`のみコンパイルされる。<br>[参考](https://www.typescriptlang.org/ja/tsconfig#types) |
|outDir  |コンパイル結果の出力先ディレクトリ。<br>未指定だとtsファイルと同ディレクトリに出力される。<br>であれば設定値としては「.build」が良さそう。  |
|outFile  |コンパイル結果を一つのファイルにまとめる（true/false）<br>outFileを指定した場合はoutDirオプションは無視される。<br>パンドラ的機能だから使わない方がいい？<br>[参考](https://qiita.com/ryokkkke/items/390647a7c26933940470#outfile)  |
|rootDir  |コンパイル対象のソースコードが含まれるルートディレクトリ。[参考](https://qiita.com/Nekonecode/items/09b26deec21a5f83adb1)  |
|baseUrl  |非絶対モジュール名を解決するためのベースディレクトリ。[参考](https://qiita.com/Nekonecode/items/09b26deec21a5f83adb1)  |
|removeComments  |TS→JS変換時にコメントを削除する(true/false※デフォルト)  |
|preserveConstEnums  |`const enum`定義をJSコンパイル時に消すか残すか（true/false)  |
|sourceMap  |ソースマップファイルの生成を有効化(true/false)。<br>コンパイル前後のマッピングJSONファイル。<br>基本trueで良さそう？  |
|allowJs  |JavaScript（.js,.jsx）ファイルをコンパイルの対象へ含めるか(true/false)<br>デフォルトだとts,tsxファイルのみコンパイルされる。<br>モジュール含めコンパイル対象のJSファイルがある場合はtrueにするべき。  |
|checkJs  |allowJsと連携動作します。checkJsが有効化されている場合、JavaScript ファイル内のエラーが報告されるようになります。  |
|moduleResolution  |tscのモジュールの名前解決の方法<br>設定値<br>・classic（moduleの指定値がAMD・System・ES2015のいずれかである場合)<br>・node（NodeJSの場合これを選ぶ）  |
|noEmit  |JavaScript ソースコード、ソースマップ、型定義のファイルを出力しないようにする。<br>じゃあ何をする？"型チェック"のみを行いたいときに「true」にする。[参考](https://stackoverflow.com/questions/55002137/typescript-noemit-use-case)  |
|jsx  |TypeScriptでJSXを使う場合のオプション。<br>設定値<br>・preserve（変換しない）<br>・react（React17以前の旧変換）<br>・react-jsxdev（React17の新変換inDEVビルド）<br>・react-jsx（React17の新変換inPRODビルド）<br>[参考](https://zenn.dev/uhyo/articles/react17-new-jsx-transform)  |
|skipLibCheck  |型定義ファイル(*.d.ts)のチェックをスキップする（true/false）<br>△型定義ファイルでエラーが出ても無視する。<br>○各ライブラリの型定義ファイルのコンパイル時間の削減<br>[参考](https://t-yng.jp/post/skiplibcheck)  |
|allowSyntheticDefaultImports  |デフォルトIMPORTできないやつをデフォルトIMPORTする時に、型チェックエラーにならないようにする。<br>```import * as React from 'react';```<br>が<br>```import React from 'react';```と書けるようになる<br>ただこの設定だけだとdefaultインポートしない状態のままなので、`esModuleInterop`をtrueにする。<br>[参考](https://qiita.com/rhirayamaaan/items/cf3d859678577ec90d7b)  |
|esModuleInterop  |defaultをエクスポートしていないモジュールを、ES Modules でデフォルトインポートできるように、コンパイル時にヘルパーメソッドを生成する。<br>interop(相互運用する)=**モジュールをTypeScript(ECMAScript)で使えるようにコンパイルするということ**。<br>[参考](https://qiita.com/rhirayamaaan/items/cf3d859678577ec90d7b)  |
|forceConsistentCasingInFileNames  |  |
|resolveJsonModule  |  |
|isolatedModules  |コンパイル対象のファイル間の関係性を一切無視して、全てのファイルを1つのモジュールとしてコンパイルする。<br>つまり、コンパイル対象の全ファイルがexport構文を含んでいる必要がある。<br>そうでないとコンパイル時にエラーを出すようにする。  |
|noFallthroughCasesInSwitch  |  |
|importsNotUsedAsValues  |  |
|suppressImplicitAnyIndexErrors |オブジェクトへインデックスアクセスしたときの暗黙的anyについてのエラーを抑止する(true/false)<br>```const obj = { x: 10 };```<br>```console.log(obj["foo"]); // エラー``` |
|noUnusedLocals  |未使用のローカル変数がエラーになる（true/false）  |
|noUnusedParameters  |利用されていない関数の引数がエラーになる（true/false）  |
|strict  |これをONにすると以下のオプションが有効になる。<br>--noImplicitAny<br>--noImplicitThis<br>--alwaysStrict<br>--strictBindCallApply<br>--strictNullChecks<br>--strictFunctionTypes<br>--strictPropertyInitialization<br>strictをtrueにした上で、任意のルールを一つずつfalseにすることが可能。 [参考](https://qiita.com/ryokkkke/items/390647a7c26933940470#strict) |
|noImplicitAny  |暗黙的にanyになる値をエラーにする(true/false)  |
|noImplicitThis |使われているthisの型が暗黙的にanyになる場合にエラーにする。 |
|alwaysStrict |"use strict";を必ず全てのファイルの先頭行に付与する。 |
|strictBindCallApply |bind, call, applyを使用する際に、より厳密に型チェックが行われるようになる。 |
|strictNullChecks  |null・undefinedの代入がエラーとなる。<br>下記のように型指定されていればOK。<br>```let name: string``` &#124; ```null;```<br>```name = null; //OK```<br>[参考](https://blog.makotoishida.com/2018/03/typescriptstrictnullchecks.html)  |
|strictFunctionTypes |TypeScriptのデフォルトはBivariantlyな挙動だが、このオプションをtrueにするとContravariantlyに型チェックが走るようになる。 |
|strictPropertyInitialization |クラス定義時、インスタンス変数の初期化が宣言時、もしくはコンストラクタのどちらでも行われていない場合にエラーになる。 |

## preserveConstEnums（TSコンパイル時にconst enum定義を消すか消さないか）

https://riptutorial.com/typescript/example/24752/preserveconstenums

・Typescriptでは下記のような`const enum`文をサポートしているが、JavaScriptにコンパイルされると消えてしまう。
>Typescript supports costant enumerables, declared through const enum.
This is usually just **syntax sugar(糖衣構文)** as the costant enums are **inlined(1行にまとめられる)** in compiled JavaScript.
```ts
const enum Tristate {
    True,
    False,
    Unknown
}

var something = Tristate.True;
```
compiles to
```js
var something = 0;
```
JavaScriptにコンパイルしてもenum定義を残しておきたい場合に、tsconfig.jsonでpreserverConstEnumsをtrueに設定すると下記のようにコンパイルされる。
```js
var Tristate;
(function (Tristate) {
    Tristate[Tristate["True"] = 0] = "True";
    Tristate[Tristate["False"] = 1] = "False";
    Tristate[Tristate["Unknown"] = 2] = "Unknown";
})(Tristate || (Tristate = {}));

var something = Tristate.True
```

# テンプレート(フロントエンド/JavaScript)
```json
{
  "compilerOptions": {
    "target": "es2020",
    "module": "esnext",
    "lib": ["es2020", "dom"],
    "jsx": "react",
    "sourceMap": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "moduleResolution": "node",
    "baseUrl": "src",
    "esModuleInterop": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["dist", "node_modules"],
  "compileOnSave": false
}
```
# テンプレート(バックエンド/NodeJS)
```json
{
  "compilerOptions": {
    "target": "es2020",
    "module": "commonjs",
    "lib": ["es2020"],
    "sourceMap": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "moduleResolution": "node",
    "baseUrl": "src",
    "esModuleInterop": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["dist", "node_modules"],
  "compileOnSave": false
}
```

# Node.js(CommonJS)でESModules構文(import/export)を扱いたい場合のtsconfig.json
ExpressをTypeScriptで書きたい時に利用。以下最低限の設定。

```json
{
  "compilerOptions": {
    "baseUrl": "./server",
    "module": "commonjs", // ES記法(import/export)で書いたものをTS→JS変換時にrequire構文に直してくれる!!
    "esModuleInterop": true
  }
}
```