【TypeScript】VSCodeでTypeScriptの開発環境を構築する

<!-- ================================================ -->
#概要
<!-- ================================================ -->
VSCodeでTypeScriptの開発環境を構築します。
具体的には、以下のことができる環境を構築します。

* ローカルホストで実行ができる
* VSCodeでデバッグができる
* ファイルを変更に応じて自動的に再コンパイルして、ローカルホストで起動中のブラウザに反映させる

---
この記事は、以下のコースの受講に伴って、備忘録として書いています。詳しく知りたい方は、是非受講してみてください。

https://www.udemy.com/share/103e4OAEYdcVlbTX4D/

<!-- ================================================ -->
#環境
<!-- ================================================ -->
* Windows10
* TypeScript 4.2.4
* VSCode
* Chrome

<!-- ================================================ -->
#構築
<!-- ================================================ -->

###先にインストールするもの
npm パッケージマネージャを使用するため、Node.js をインストールします。
https://nodejs.org/ja/

コマンドプロンプトを使用して、Typescript をインストールします。
https://typescript-jp.gitbook.io/deep-dive/getting-started

```
npm install -g typescript
```

###VSCode 拡張機能
VSCodeでは、以下の拡張機能をインストールします。

[Debugger for Chrome](https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome)
![無題1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358498/69d31ded-7fa3-c5cd-5ce4-28c4852e4dd0.png)


[Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer)
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358498/bb1dc354-c0b3-6469-777f-62b1c972670d.png)


###ファイル作成
####作業フォルダの初期化
作業フォルダを作成して、VSCodeで開きます。
VSCodeで、[ターミナル]タブ - [新しいターミナル]でターミナルを開きます。（作成したフォルダがカレントディレクトリになっています）
以下を実行します。

```package.jsonの作成
npm init -y
```

```tsconfig.jsonの作成
tsc --init
```

####tsconfig.json
作成されたtsconfig.jsonを設定します。

```tsconfig.json
{
  "compilerOptions": {
    /* Basic Options */
    "target": "ES6",
    "module": "ES2015",
    "sourceMap": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "removeComments": true,
    "noEmitOnError": true,

    /* Strict Type-Checking Options */
    "strict": true,

    /* Additional Checks */
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,

    /* Module Resolution Options */
    "esModuleInterop": true,

    /* Experimental Options */
    "experimentalDecorators": true,

    /* Advanced Options */
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  }
}
```

特に、`"target": "ES6"`、`"module": "ES2015"`、`"sourceMap": true`であることに注意してください。
後述するESモジュールを使用するためには、ES2015（ES6）以降を指定する必要があります。

その他の設定については、以下を参照してください。
[tsconfig.jsonの全オプションを理解する（随時追加中）](https://qiita.com/ryokkkke/items/390647a7c26933940470)

####index.html, src/app.ts
tsconfig.jsonで、`"rootDir": "./src"`としたのでsrcフォルダのTypeScriptファイルをコンパイルします。
なので、以下のファイルを追加します。

* index.html
* src/app.ts

![無題2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358498/59ab5131-9bbd-1f90-c1e5-0b9b909d4d93.png)

```index.html
<!DOCTYPE html>
<html lang="ja">
	<head>
		<meta charset="UTF-8" />
		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<script src="dist/app.js" defer></script>
		<title>Document</title>
	</head>
	<body></body>
</html>
```
`script src`には、tsconfig.jsonの`"outDir": "./dist"`で設定した出力先のフォルダを指定します。
また、コンパイルされるファイルは`app.ts`なのでコンパイル後の`app.js`を指定します。

```app.ts
console.log('Hello, TypeScript');
```

<!-- ================================================ -->
#コンパイル＆デバッグ
<!-- ================================================ -->
###コンパイル
ターミナルで以下を実行して、コンパイルを行います。

```
tsc
```
そうすると、`dist`フォルダ内に、`app.js`、`app.js.map`が作成されます。

![無題3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358498/09b1d9f6-ebda-ced1-e6e4-e0ffbdbde311.png)

`app.js.map`は、デバッグ時に使用するファイルで、コンパイルされたjsファイルと元のtsファイルのコード位置を紐づけるファイルです。
もう少し詳しく言うと、ブラウザ上ではjsファイルしか動かないため、元のtsファイルでブレークポイントを使ってデバッグするためにマッピングするためのファイルです。

###デバッグ
[実行とデバッグ]メニュー - [launch.jsonファイルを作成] - [Chrome]を選択します。
![無題4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358498/3c650764-c7c9-d78f-33e4-0eac520e8fbf.png)

`.vscode/launch.json`が作成されるので、以下のように変更します。

```launch.json
{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "pwa-chrome",
            "request": "launch",
            "name": "Launch Chrome against localhost",
            "url": "http://localhost:5500",  // ここを 5500 に変更
            "webRoot": "${workspaceFolder}"
        }
    ]
}
```

これで、準備ができました。デバッグします。

**1）右下の[Go Live]ボタンを押します**
![無題5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358498/0dfa6c89-2ba9-1f26-f196-1d9cf7abac5e.png)

そうすると、ポート番号が表示されます。もし`launch.json`で指定した値と違う場合は、launch.jsonを修正してください。
![無題6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358498/06814bb0-e637-d364-6674-651c2a87e653.png)

また、新しいタブでChromeが起動しますが、それは閉じてください。

**2）F5を押してデバッグします**
F5を押すと、再度Chromeのタブが表示されます。
F12を押して、ディベロッパーツールの[Console]タブをみると、app.tsで記述したconsole.log()内容が表示されています。
![無題7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358498/64367ae0-069e-826e-ac27-7ff571c74889.png)

次に、app.tsにブレークポイントをいれて、再実行（ブラウザをリロード）します。
そうすると、ブレークポイント位置で処理が止まることがわかります。これは、tsconfig.jsonで`"sourceMap": true`にして、`app.js.map`を作成しているからです。
![無題8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358498/03b65a93-5677-3908-49be-e639f23a7032.png)

**3）app.tsの再コンパイル**
デバッグ実行をした状態（ブラウザを起動した状態）で、app.tsを以下のように変更します。

```app.ts
console.log('Hello, TypeScript');
console.log('こんばんは！'); // 追加
```

ファイルを保存して、`tsc`コマンドでビルドします。
そうすると、ブラウザが自動的にリロードされ、変更したコードが反映されます。（ここでは、Consoleに「こんばんは！」と表示されます）

###watchモード
app.tsを変更するたびにいちいち`tsc`コマンドを打つのは面倒くさいです。
そこで、`watchモード`をしようします。
ターミナルで以下を実行します。

```
tsc -w
```

そうするとファイルの変更を監視して、保存時に自動で再コンパイルされるようになります。
watchモードを停止する場合は、ターミナルで`Ctrl + C`を押します。

<!-- ================================================ -->
#ESモジュール
<!-- ================================================ -->
プロジェクトが大きくなると、ひとつのファイルでコードを管理するのは現実的ではありません。
そこで機能ごとに、コードを分割してモジュール化します。

ここでは、`src/modules/sub.ts`ファイルを追加し、モジュールとしてapp.tsで呼びだします。

![無題9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358498/f1492ad1-4bdd-34b2-9cbd-59503b852a20.png)

ファイルを以下のようにします。

```json:tsconfig.json（再記）
"target": "ES6"
"module": "ES2015"
```
```sub.ts
export function greeting(name: string) {
	console.log(`Hello! ${name}`);
}
```
```app.ts
import { greeting } from './modules/sub.js';

console.log('Hello, TypeScript');
console.log('こんばんは！');

greeting('Nemutas');
```
importするモジュールは、コンパイル後の`jsファイル（拡張子つき）`を指定する。

```index.html
・・・
<script type="module" src="dist/app.js" defer></script>
・・・
```
scriptに`type="module"`を指定する。


これで、`tsc`コマンドでビルドを行うと、上図のように`dist/modules/sub.js, sub.js.map`が作成されます。
また、デバッグ実行をおこなうと、ブラウザのConsoleでgreetingメソッドの内容が実行されているのがわかります。

###問題点
ESモジュールの問題点は、コンパイルしたjsファイルをバンドル（単一化）できないところにあります。
バンドルができないので、コンパイルするJavaScriptは、import/export構文をサポートしているバージョン（ES6/ES2015以降）でなければなりません。つまり、レガシーなブラウザでは動作しない可能性があります。
また、複数のjsファイルを読み込む必要があるため、その分httpリクエストが増え、読み込みに時間がかかるようになります。
そして、コンパイルされたファイルは最適化（ミニファイ）されないため、ファイル容量もかさみます。

ESモジュールの問題点をまとめると、

* バンドルされない
* モダンなブラウザでしか動作しない
* ブラウザで読み込みに時間がかかる
* ミニファイされない

これを解決するのが、**モジュールバンドラー（webpack）**です。

webpackを使用した開発環境を構築については、以下でまとめました。
[【TypeScript】VSCodeでTypeScriptの開発環境を構築する②（webpack ver.5）](https://qiita.com/nemutas/items/3a220aad4692f83bbbb5)

<!-- ================================================ -->
#Tips
<!-- ================================================ -->
###tsconfig.jsonのいくつかの設定

`"removeComments": true`
コンパイルするときに、コメントを除外する

`"noEmitOnError": true`
コンパイルするときに、tsファイルにエラーがある場合はコンパイルしない

`"noUnusedLocals": true`
未使用のローカル変数がある場合は、エラーとする

`"noUnusedParameters": true`
未使用の関数パラメーターがある場合は、エラーとする
回避方法は、この設定をfalseにするか、使わないパラメーターをワイルドカード(`_`始まりのパラメーター名)にする

`"noImplicitReturns": true`
暗黙的な関数リターンがある場合、エラーとする
どこかしらで値を返す関数について、明示的にreturnを書く必要がある

`"experimentalDecorators": true`
デコレータを使用できるようにする
デコレータについては、[TypeScriptによるデコレータの基礎と実践](https://qiita.com/taqm/items/4bfd26dfa1f9610128bc) を参照してください

<!-- ================================================ -->
#参考
<!-- ================================================ -->
* [【世界で7万人が受講】Understanding TypeScript - 2020年最新版](https://www.udemy.com/share/103e4OAEYdcVlbTX4D/)
* [tsconfig.jsonの全オプションを理解する（随時追加中）](https://qiita.com/ryokkkke/items/390647a7c26933940470)
* [TypeScriptによるデコレータの基礎と実践](https://qiita.com/taqm/items/4bfd26dfa1f9610128bc)