React + Typescriptで開発するメリット

#１・はじめに
私がReactの開発にTypescriptを導入するようになってしばらく経ちましたが、Reactの開発にTypescriptを導入することはメリットが多くあると感じますので、皆さんにも共有したいと思います。

今回の例で使用したコードをGithubにもアップしましたので、この記事を見ながらご自分で試してみる等有効活用していただけたら嬉しいです。
　　[今回使用したコード](https://github.com/uwattotaitai/benefit-of-react-typescript)

#２・React+Typescriptのメリット

##・トランスパイルする前にエラーを表示してくれる

Typescriptは静的型付け言語であり、変数等に予め型を定義する必要があります。
これはReactにTypescriptを使用する時も例外ではなく、Reactの**「props」**と呼ばれるコンポーネント間で受け渡す任意の値や、コンポーネント内で使用する関数にも事前に型を定義する必要が出てきます。
予め定義をすることで、渡されるはずの値が渡されていないときや、渡される値の型が間違っていた時に「プログラム実行前」にエラーを起こして警告してくれるようになります。

```typescript:Sample.tsx
import { VFC } from 'react'

interface SampleProps {
    number: number; //必須項目
    string: string; //必須項目
    boolean?: boolean //必須ではない
}

const Sample1: VFC<SampleProps> = (props) => {
    return (
        <>
            <h2>プロップスの候補表示</h2>
            <div>number is {props.number}</div>
            <div>string is {props.string}</div>
            <div>boolean is {props.boolean}</div>
        </>
    );
}
export default Sample1;

```

例では「Sample」というコンポーネントを作成し、それぞれ必須項目として`number`、`string`、必須ではなく任意で`boolean`というpropsを受け取るよう設定しました。
ここでインターフェース`SampleProps`から`number`の定義を消去してみると、
![Screenshot from 2021-03-15 15-14-54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574551/f943a42b-71d2-0dd2-a1a0-aee75ff4d82b.png)
Typescriptに怒られてしまいましたね。これは`SampleProps`に`number`という値は定義されていないよ！ということです。

```typescript:app.tsx
import React from 'react';
import Sample from './component/Sample';

function App() {
  return (
    <>
      <Sample1 
        number={1}
        string={'サンプル'}
      />
    </>
  );
}
```

次の例では、`app.tsx`で先程定義したコンポーネントを使用し、`props`に必要な値を渡しています。
先程定義したコンポーネント`Sample`では、`number`、`string`は必須になっていました。試しに渡していた2つのpropsを消去してみると、
![Screenshot from 2021-03-15 15-30-39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574551/661fe960-f2ab-bb24-dcf0-c02ef459e754.png)
このようにインターフェース`SampleProps`で必須項目に指定してた`number`、`string`がありませんよ！としっかり警告を出してくれます。
`boolean`は`?`を付与して「必須項目ではない」ということを定義していましたので、値が渡されなくても警告は出ません。
また、propsに定義していた型とは違う型の値を渡すと、
![Screenshot from 2021-03-15 15-31-14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574551/f1cdecb3-9b21-26fa-9acf-636c84be1576.png)
これもTypescriptがしっかり警告を出してくれました。
このようにTypescriptによって事前に型定義をすることで、型安全になるだけではなく**「propsに値を渡し忘れた」**などのヒューマンエラーもプログラム実行前にリアルタイムで検出してくれるため、効率良くコードを記述できるようになります。

##・候補表示（コードサジェスチョン）

Typescriptを使用して型定義をすると、IDEのインテリセンス機能によって**インターフェース、型定義ファイルに記述されている値、メソッド等が候補として表示されるようになります。**

先程の`Sample`コンポーネントを例に出すと、インターフェース`SampleProps`にて定義した値が候補として表示されるようになります。
![Screenshot from 2021-03-15 16-05-06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574551/352c6ab9-5f67-be92-bfac-5ed696a10e09.png)
画像の通り、「props.」と入力したらインターフェースで定義された値が候補に表示されているのがわかりますね。
 
```typescript:SampleForm.tsx
const submitSampleForm = (e: FormEvent) => {
        e.preventDefault();

        console.log(variables);
    }
```
次の例は、フォーム実装する時によくある、onSubmitイベントが発生した場合の処理を簡単に記述した関数です。
例では、引数eに@types/reactという型定義ファイル（事前にインストールしています）の中の「FormEvent」という型を使用しています。それによって、FormEventで定義されている値、メソッド等が候補に表示されます。
![Screenshot from 2021-03-15 16-54-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574551/603e62fc-96e8-0fc0-d038-3406ff759c44.png)

##・関数がドキュメントのようになる+参照できる

Typescriptを使用し型を定義することによって、自作の関数、ライブラリで用意されている関数の引数、戻り値の型が参照できるようになります。

```typescript:sampleFunction.ts
export const sampleFunction = (a: number, b: number): number => {
    return a + b;
};
```

例では引数にnumber型を取る`a`、`b`、戻り値には`number`型を返す`sampleFunction`という関数を定義しました。
この関数を呼び出して関数にカーソルを合わせるだけで、関数の引数、戻り値の型を簡単に確認することができます。

![Screenshot from 2021-03-16 10-16-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574551/b46b877a-ae43-3cf0-bea5-216b4d14a0fc.png)

この機能は自作の関数はもちろんライブラリで定義されている関数を使用する時には大変便利で、カーソルを合わせて引数や戻り値を見ればどういう風に関数を使えばよいかわかるほか、ライブラリによっては型定義ファイルにコメントで関数の機能を詳細に説明してくれていることがあり、関数にカーソルを合わせると引数や戻り値とともにそのコメントも表示されるので、いちいちライブラリのドキュメントを見て確認することが減ります。
また、ctrl(command)+左クリックすれば関数やコンポーネントの定義元まで飛ぶこともできます。

![Screenshot from 2021-03-15 17-05-14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574551/fd00891d-923e-404c-5536-d7f854de7ae3.png)

画像は`Sample`コンポーネントでctrl(command)+左クリックしてSampleコンポーネントの定義元を参照しています。
このようにTypescriptを使用し型を定義するorライブラリの型定義ファイルをインストールすると、開発者にとってメリットが大きいことがわかります。

#３・メリットは分かった。でも・・・？
##・Typescriptって難しいんじゃないの？？

これは個人によって難易度の感じ方は変わると思いますが、TypescriptはJavascriptのスーパーセット（上位互換）の言語で、**型定義をする部分以外はJavascriptの構文がそのまま使える**ので、個人的にはそこまで難易度が劇的に跳ね上がるような感じはありませんでした。静的型付け言語の経験が無い方は最初型定義に苦労するかもしれませんが、やればやるほど自分のコーディングの効率が上がっていることを実感できると思います。

##・いちいち全部型定義しなくちゃいけないの？？

Typescriptには**型推論**という素晴らしい機能があり、変数等の前後の文脈から型を推論し自動的に宣言してくれます。

![Screenshot from 2021-03-16 09-41-11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574551/2d2cd225-94c3-d96e-4b9a-90d48008cbbf.png)

画像は`SampleForm`コンポーネントのonChangeイベントで宣言した変数にカーソルを合わせたものです。
eという変数に型を宣言していないのに、Typescriptは適切に型を推論して宣言してくれています。
もちろん全てに型推論が効くわけではありませんが、型推論の機能によって自分が型定義をする機会が減りますので、自分が全て型定義をするということは無いです。


##・そこまでガチガチに縛られたくないんだけど・・・・

Typescriptで開発する際は`tsconfig.json`という設定ファイルをプロジェクトに置くことが必要になります。

```json:tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true, .//jsファイルをts.tsxファイルと共存させることができるようになる
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "include": [
    "src"
  ]
}

```

[tsconfig.jsonドキュメント](https://www.typescriptlang.org/ja/tsconfig)
このファイルにTypescriptにチェックしてもらいたい項目を記述します。
Typescriptを段階的にプロジェクトに導入したい場合は上の例のように`allowJs: true`を設定して`.js`と`.ts.tsx`ファイルを共存させることもできますし、今よりももっと厳格にチェックして欲しい場合は項目を追加したり、もっと緩くして欲しい場合は`strict: false`にしたり、開発者の要望に沿って柔軟に仕様は変えられるようになっています。


##・導入が面倒臭そう・・・・
Reactで新たにプロジェクトを作成する時に`create-react-app`を用いてプロジェクトを作成するならば、`--template typescript`をつけるだけで簡単にプロジェクトにTypescriptを導入できます。

```
npx create-react-app [任意のプロジェクト名]　--template typescript
```

プロジェクト内にサードパーティのライブラリをインストールする時もライブラリに加えて`@types/ライブラリ名`で型定義ファイルをインストールする(ライブラリにビルトインで組み込まれている場合もあり、その場合は型定義ファイルはありません。)だけです。

```
npm i --save-dev @types/[ライブラリ名]
yarn add -D @types/[ライブラリ名]
```

たったこれだけで開発者はコード補完等の型定義による恩恵を受けることが可能になります。


#４・まとめ

私がReactにTypescriptを導入した時は型定義に苦戦し、「面倒くさくなってるだけじゃん、本当に効率良くなるの?」と思っていましたが、今ではTypescriptがなければ開発したくないほどハマってしまいました(笑)
まだReactにTypescriptを導入したことがない方は是非この機会に導入してみることをお勧めします。