TypeScript 導入～いろいろなパターンをまとめてみた～

# はじめに
Typescriptを導入したい（使いたい）けど、どうやってやればいいの？っていう人のための記事です。

## TypeScriptとは
TypeScriptは、JavaScriptの代替となるべくマイクロソフトによって開発されたオープンソースのプログラミング言語です。特徴は、大規模なアプリケーションの開発に耐えるように、(C++やJavaなどの)クラスベースのオブジェクト指向プログラムの機能や、変数への静的な型の指定などを取り込んで、設計されています。それはJavaScriptの標準仕様であるECMAScript2015以降の新機能を先取りした形にもなっています。

## なぜTypeScriptを使うのか
[TypeScriptを使う理由](https://qiita.com/mugichan3/items/a0f17d9f4f757d88a83a)にも書いているんですが、
JavaScriptは

- クラス定義がない
- functionという記述が長過ぎる
- パッケージ管理が標準で存在しない
- 型がない

とのことです。僕は「型がない」ときて、確かにJavaScriptは型がないから、変数定義や関数定義でも、この変数はどういうものかが一目でわかりにくいなあ～～と思ってTypeScript始めました。

## 導入方法(全3パターン)

- 単純にTypescriptを試したい
    - TypeScript用のコンパイラを用意してTypeScriptファイルをJavaScriptファイルに変換する。
- babel(タスクランナー)でTypescriptを導入したい
    - babelでtypescriptもサポートされているので、その導入方法を紹介。
    - 他のタスクランナー（webpack,gulp,percel）でもTypeScriptの対応は可能
- JSフレームワークにTypescriptを導入したい
    - Vue.jsやReact等のフレームワークを用いる場合で、JavaScript→TypeScriptに変更したい場合
        - この記事ではReact + TypeScriptで導入します。

## :point_up:単純にTypescriptを試したい
まず、TypeScript → JavaScriptに変換するためのコンパイラが必要です。
TypeScript用のコンパイラのことを`tsc`と表記する場合もあります。
手順としては、

**Node.jsインストール→TypeScript用のコンパイラをインストール→TypeScriptファイルをJavaScriptファイルに変換**という手順です。
### 環境
Node.js

### 導入手順
1. Node.jsをインストール
   - 毎度おなじみNode.jsのインストールです。Node.jsの[公式サイト(https://nodejs.org/ja/)](https://nodejs.org/ja/)よりインストーラーをダウンロードして、インストールしてください。ダウンロードできるバージョンは二種類ありますが、推奨版をインストールします(以後、Node.jsのインストールと同時にインストールされるnpmはどのパターンでも使用します)。

2. TypeScriptコンパイラをインストール
    - ターミナルを立ち上げて、下記のコマンドを実行してください。
        - ```npm install -g typescript```
    - OSや環境によっては`sudo`コマンドを先頭につける必要があるかもしれません(`sudo`は権限付きで実行するコマンドで、実行後にOSのログインパスワードを入力する必要があります)。 
        - ```sudo npm install -g typescript```

3. インストールの確認
    - 続いてコマンド"tsc -v"と実行し、"Version 〇.〇.〇"などと表示されればインストールは完了です。

```JavaScript:hello.ts
const message:string = 'Hello World!';
console.log(message);
```

ターミナルで、下記のコマンドを実行してください。

```terminal:コマンドプロンプト
tsc hello.ts
```

うまくコンパイルできると、結果として"hello.ts"と同じ階層に"hello.js"というファイルができているはずです。エディタでコンパイル結果を確認してみてもいいでしょう。
動作確認として、ここでは簡単にNode.jsで実行してみましょう。次のコマンドを入力してください。

```terminal:コマンドプロンプト
node hello.js
```

実行すると、ターミナルで”Hello World!”と表示されます。

## :point_up:babel(タスクランナー)でTypescriptを導入したい
babel単体でtsのビルドができるので、その方法です。
（**※babelはtypescriptから型情報を取り除くだけなので型チェックまではサポートしておらず、型チェックに関してはtsc(TypeScript用のコンパイラ)経由で行う必要**）
今回はbabel + webpack + typescriptで作成していきましょう。

### 環境
Node.js
webpack
babel

### 導入手順
まず、適当にフォルダを作成します。それと`npm init`で初期ファイル(package.json)を追加します。

```sh
$ mkdir babel-typescript-sample && cd babel-typescript-sample
$ npm init
```

package.jsonが作成されたら必要なmoduleをインストールしていきます。

```sh
$ npm install -g typescript webpack webpack-cli webpack-dev-server
$ npm install --save-dev @babel/core @babel/preset-env babel-loader ts-loader
```
###  typescript側の設定
#### tsconfig.jsonの作成
typescriptのビルドやチェックのルールを設定するファイルです。
以下のコマンドでディレクトリに作成されます。

```sh
$ ./node_modules/.bin/tsc --init
```
上記コマンドにてプロジェクトルートに`tsconfig.json`が作成されていると思います。

#### tsconfig.jsonの設定
configに設定できる項目はたくさんありますが、とりあえずこれらを設定しておけば良いと思います。
型チェックや不要な変数のチェックなどはtsconfig側の設定になります。

tsconfig.jsonの中身のプロパティもより知りたい場合は下記URLを参照してください。

（参考）
[tsconfig 日本語訳](https://qiita.com/alfas/items/539ade65926deb530e0e)
[jsStudio:tsconfig.json](http://js.studio-kingdom.com/typescript/project_configuration/tsconfig_json)

```js:tsconfig.json
{
  "compilerOptions": {
    "target": "ESNEXT",                    /* TSを書くときにどのversionのESが対象か: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
    "module": "ESNext",                    /* どのversionのESを生成するか: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
    "strict": true,                        /* すべての strict タイプ・オプション(noImplicitAny, strictNullChecks, noImplicitThis(thisの型チェック), alwaysStrict(strictモードのjs出力)) を 有効化する */
    "noImplicitAny": true,                 /* any型の使用不可 */
    "strictNullChecks": true,              /* nullable型以外でnullを許容しない */
    "noUnusedLocals": true,                /* 未使用の変数を許容しない */
    "noUnusedParameters": true,            /* 未使用の変数を許容しない */
    "noImplicitReturns": true,             /* メソッド内で返り値の型があっているかをチェック */
  }
}
```

### babelの設定
まずはプロジェクトルートに.babelrcを作成します。

```sh
$ touch .babelrc
```

中身はこのような感じです。
(※react等のフレームワークでbabelを設定する場合は別途設定が必要)

```json:.babelrc
{
  "presets": [
    "@babel/preset-env"
  ]
}
```
### webpackの設定
- webpack
  - JSのビルドツール。import/exportやrequire()をブラウザ用にバンドルしてくれたりする。
  - webpack v4.0から`mode`は必須。
- ts-loader
  - webpackの中でts(tsx)ファイルをjsに変換してくれるツール

まずは以下のコマンドでファイルを作成します。

```sh
$ touch webpack.config.js
```

```js:webpack.config.js
module.exports = {
  mode: process.env.NODE_ENV || "development",
  entry: "./src/index.ts",
  output: {
    filename: "bundle.js",
    path: __dirname + "/dist"
  },
  resolve: {
    extensions: [".ts", ".tsx", ".js", ".json"]
  },
  module: {
    rules: [
      {
        test: /\.ts?$/,
        use: [
          { loader: "babel-loader" },
          { loader: "ts-loader" }
        ],
        exclude: /node_modules/
      }
    ]
  },
};
```

今回は`src/index.ts`をビルドし、`dist/bundle.js`として出力するように記載しています。

### ビルド用のtypescriptファイル準備
試しにビルドする用のtypescriptを用意しましょう。
今回は`src/index.ts`を用意し、`dist/bundle.js`として出力したいので準備をします。

```sh
$ mkdir src dist
$ touch src/index.ts
```

中身は適当なtypescriptファイルで（いつものHello World）。

```typescript:index.ts
const message:string = 'Hello World!';
console.log(message);
```

### package.jsonへscript設定
あとはこれらを実行するのですが、package.jsonのscript項目に記載しておけば、
`npm run [タスク名]` で実行可能です。うまくいけば`dist/bundle.js`が出力されていると思います。
あとはそのファイルをhtmlファイルで読み込んでやるとコンソール上に`Hello World!`が出力されます。


## :point_up:JSフレームワークにTypescriptを導入したい
JSフレームワークといえば、Angular,React,Vueですね。（Elmも熱い！！！）
Angularに関してはデフォルトがTypeScriptなので良いとして、さて、ReactとVueでTypeScriptを導入するときはどうすればいいのか。Vueに関して言えば下記コマンドから、TypeScriptを選択すれば大丈夫です。
（TypeScript で書きたいので、「**Manually select feature**」を選択）

```
$ vue create my-project-name
```

なんかVue.jsの場合だとコマンド1つ打って、TypeScriptを選択すればうまくいくんですが、Reactの場合だとコマンド1つ打って、はい、「TypeScript + React環境出来たよ～～」とはならないので、Reactで試してみた。（といってもbabel環境と似ているところもややあります。）

### 環境

- NodeJS 
- React 
- TypeScript 
- webpack 

### 導入手順
まず適当に「react-ts-sample」というフォルダを作りましょう。その中に色んなファイルがあります。
とりあえず作っておいてください。

```
$ cd react-ts-sample
$ tree .
.
├── index.html
├── package.json
├── src
│   ├── Hello.tsx
│   └── index.tsx
├── tsconfig.json
└── webpack.config.js
```
※webpack.config.jsは下記に記載していますが、開発用向けの設定ファイルです（例：`devtool: 'source-map'`）。

```js:webpack.config.js
module.exports = {
  entry: './src/Index.tsx',
  output: {
    filename: './dist/bundle.js'
  },

  devtool: 'source-map',

  resolve: {
    extensions: ['.ts', '.tsx', '.js']
  },

  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: [
          {loader: 'ts-loader'}
        ]
      }
    ]
  }
};
```
### インストール
インストールは`package.json`に記載し、あとで`npm install`して追加しましょう。
(`devDependencies`や`dependencies`にインストールしたいパッケージを追加する)

```json:package.json
{
  "name": "react-typescript-redux",
  "version": "1.0.0",
  "license": "MIT",
  "scripts": {
    "build": "webpack --colors --config ./webpack.config.js",
  },
  "devDependencies": {
    "@types/react": "15.0.39",
    "@types/react-dom": "15.5.1",
    "ts-loader": "2.3.2",
    "typescript": "2.4.2",
    "webpack": "3.4.1"
  },
  "dependencies": {
    "react": "16.0.0-beta.1",
    "react-dom": "16.0.0-beta.1"
  }
}
```

### ツール
- `@types`
  - TypeScript用の型定義ファイル
    - ※Babelの設定でもありましたが、ts-loader等のモジュールも追加しましょう。

### `@types`

型定義については、TypeScript2.0系から、npmパッケージとして型定義が提供されるようになりました。バージョン管理もnpmに任せられるという点だけでも十分すごいらしい。

### tsconfig.json
Babelのところでもでてきましたが、TypeScriptのコンパイルをするときに必要な設定ファイルです。
ブラウザにおいてはES Modulesが主流なので、 `"module": "ES2015"` で動くようにしておきましょう。

```json:tsconfig.json
{
  "compilerOptions": {
    "strictNullChecks": true,
    "noUnusedLocals" : true,
    "noImplicitThis": true,
    "alwaysStrict": true,
    "outDir": "./dist/",
    "sourceMap": true,
    "noImplicitAny": true,
    "lib": ["dom", "ES2017"],
    "module": "ES2015",
    "target": "es5",
    "jsx": "react"
  }
}
```

### コード
HTMLファイルとTypeScriptファイルを作っていきましょう。

```html:index.html
<!DOCTYPE html>
<html>
<head>
  <title>React + TypeScript Sample</title>
</head>
<body>
<div id="app"></div>
<script src="dist/bundle.js"></script>
</body>
</html>
```

```ts:src/index.tsx
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import Hello from "./Hello";

ReactDOM.render(<Hello content="hello world!"/>, document.getElementById('app'));
```

```ts:src/Hello.tsx
import * as React from 'react';

export interface Props {
    content: string;
}

export default class MyComponent extends React.Component<Props, {}> {
    render() {
        return <div>{this.props.content}</div>
    }
}
```

### Buildしてみる

まずは `npm install` しましょう。するとpackage.jsonに書いているモジュールを読み取りインストールします。これでreactなどのパッケージと型定義ファイルがダウンロードされます。ダウンロード完了後、下記コマンドを実施しましょう。

```sh
$ npm run build
```
`dist/bundle.js` と、そのソースマップが吐かれます。
あとはindex.htmlを開くと、bundle.jsが読み込まれて、画面に「hello world!」が表示されます。

## TypeScriptを触ってみよう
ここからはTypeScript文法を一覧でまとめました。
TypeScriptは「JavaScriptのスーパーセット」なのでJavaScriptの文法はほぼ使えます。それらの文法と「**インターフェース、アクセス修飾子、タプル**」といったTypeScriptの独自機能をマスターしましょう。自分自身参考になったQiitaの記事を一覧でしています。非常に分かりやすかったです。

〇TypeScriptの型入門
https://qiita.com/uhyo/items/e2fdef2d3236b9bfe74a

〇TypeScript入門
https://qiita.com/ringtail003/items/7ccf992f18b768e0e633

〇TypeScriptでクラスを扱った後、さらにコードを短くしてみる(set/get/class)
https://qiita.com/ryo-ma/items/44c2dd522c98f4ae7ba8

〇Typescriptのインターフェースの使い方
https://qiita.com/nogson/items/86b47ee6947f505f6a7b

また、追々文法も自分なりにまとめていきたいですね。

## まとめ
導入方法をまとめました。

(**必須**)

- Node.js(npm or yarn)をインストール
- typescript用のモジュールをインストール

（**時と場合によって（ほぼ必須）**）

- tsconfig.jsonを作る。
- webpackの設定ファイルを作る。
- package.jsonに色々書く。

フロントエンドを取り巻く環境はタスクランナーやフレームワークと多種多様で、好みで分かれる場合もあると思います。TypeScriptもフロントエンドの中で好みで使っている人も見受けられ、決して必須ではありませんが、メンテナンス面やプロジェクトの引継ぎを考えると、JavaScriptよりもコードが見やすい点で優れている（型が一目でわかって便利）と思います。なので必須ではありませんが、この記事を読んで、「これから使っていこう！」ってなれば幸いです。