create-react-appを使ったTypeScriptのチュートリアル

Reactにまだ慣れていない、TypeScriptを今からはじめて触れる人向けに、簡単なチュートリアルを書きます。
この記事の他にもTypeScriptのチュートリアル記事はいくつかありますので、そちらも参考にどうぞ

[TypeScriptチュートリアル① -環境構築編-](https://qiita.com/ochiochi/items/efdaa0ae7d8c972c8103)
[TypeScript チュートリアル](https://qiita.com/EBIHARA_kenji/items/31b7c1c62426bdabd263)

今回はReduxや、Sagaなどのミドルウェアは一切使わずにとてもシンプルなアプリケーションを作ります。

##環境構築

`create-react-app`を使えばReactの環境構築は簡単にできます。
https://github.com/facebook/create-react-app

今回はTypeScriptを使うので下記のようにコマンドを入力します

```
npx create-react-app sample-app --typescript
```
上のコマンドの`sample-app`の部分がフォルダ名になります。
create-react-appで作成したフォルダに移動してアプリケーションを起動します

```
cd sample-app/
npm start
```

これでとりあえず初期画面が表示されました。簡単。
<img width="1436" alt="スクリーンショット 2019-07-19 15.53.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439548/6f5f6128-a6d7-2cde-4543-c9edda090679.png">

##コンポーネントを編集してみる
最初に表示されている画面のコードは`src/App.tsx`に記載されています。

```React:App.tsx
import React from "react";
import logo from "./logo.svg";
import "./App.css";

const App: React.FC = () => {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.tsx</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
};

export default App;
```
Reactの開発は基本的にsrcフォルダ内に書いていきます。
まずはこの`App.tsx`をもっとシンプルなものに書き換えます。

```React:App.tsx
import React from "react";

class App extends React.Component {
  render() {
    return <p>Hello world</p>;
  }
}

export default App;
```
<img width="1425" alt="スクリーンショット 2019-07-19 16.11.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439548/3ed206d8-0a30-e664-ff4f-389687c12e88.png">

Hello worldが表示されるだけのシンプルな画面になりました。

別のコンポーネントを作成してApp.tsxにimportしてみます。

```React:Sample.tsx
import React from "react";

class Sample extends React.Component {
  render() {
    return <p>２つ目のコンポーネント</p>;
  }
}

export default Sample;
```
```React:App.tsx
import React from "react";
import Sample from './Sample'

class App extends React.Component {
  render() {
    return (
      <p>Hello world</p>
      <Sample/>
    );
  }
}

export default App;
```
これで立ち上げてみます。

```
Failed to compile.

./src/App.tsx
  Line 9:  Parsing error: JSX expressions must have one parent element
```
エラーになりますね。
エラー内容の通り、jsxでは一つの親要素が必要となります。
`<React.Fragment>`で全ての要素を囲むことでこのエラーを回避できます。

```React:App.tsx
import React from "react";
import Sample from "./Sample";

class App extends React.Component {
  render() {
    return (
      <React.Fragment>
        <p>Hello world</p>
        <Sample />
      </React.Fragment>
    );
  }
}

export default App;
```
これで問題なく画面が表示されました。
<img width="1440" alt="スクリーンショット 2019-07-19 16.22.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439548/34b6cfa5-60d1-a945-61ac-e80330e3411d.png">

##Propsを使ってみる
ReactにはPropsとStateという２つの変数が存在します。
ふたつの変数の違いについてはこちらの記事をどうぞ。
[React における State と Props の違い](https://qiita.com/kyrieleison/items/78b3295ff3f37969ab50)
[今からはじめるReact.js〜propsとstate、それからrefs〜](https://qiita.com/kuniken/items/a22adda392ccc30011b1)

先程作成したSample.tsxにApp.tsxから変数を渡してみましょう。

```React:App.tsx
import React from "react";
import Sample from "./Sample";

class App extends React.Component {
  render() {
    return (
      <React.Fragment>
        <p>Hello world</p>
        <Sample num={"5"} />
      </React.Fragment>
    );
  }
}

export default App;
```
ここではnumという変数に"5"という文字列を代入しています。

```React:Sample.tsx
import React from "react";

class Sample extends React.Component {
  render() {
    return <p>{this.props.num}つ目のコンポーネント</p>;
  }
}

export default Sample;
```
またエラーになりました。

```
Type '{ num: string; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<Sample> & Readonly<{}> & Readonly<{ children?: ReactNode; }>'.
  Property 'num' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<Sample> & Readonly<{}> & Readonly<{ children?: ReactNode; }>'.  TS2322

     7 |       <React.Fragment>
     8 |         <p>Hello world</p>
  >  9 |         <Sample num={"5"} />
       |          ^
    10 |       </React.Fragment>
    11 |     );
    12 |   }
```
Typescriptでは型をちゃんと指定してあげなければなりません。
Sample.tsxを以下のように書き換えてみましょう。

```React:Sample.tsx
import React from "react";

interface Props {
  num: string;
}

class Sample extends React.Component<Props> {
  render() {
    return <p>{this.props.num}つ目のコンポーネント</p>;
  }
}

export default Sample;
```
これで変数numがstring型であることを定義できました。
エラーも解消され、問題なく画面が表示されます。
<img width="1440" alt="スクリーンショット 2019-07-19 16.33.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439548/51289cd6-fd3f-3252-3f8e-0f39e01c8540.png">

##Stateを使ってみる
App.tsxを書き換えて、Stateを使って何かしら値を画面に出力してみます。
<img width="1431" alt="スクリーンショット 2019-07-19 16.45.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439548/6ef34633-6bdf-db0a-e4b5-6e37779fa36d.png">
<img width="1411" alt="スクリーンショット 2019-07-19 16.45.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439548/ffc6f8d2-0607-f279-b0cc-b1394945945c.png">
ボタンを押下されたら文言が変わるという単純な実装をしてみました。
JavaScriptを使ったReactならこのように書くと思います。

```React:App.tsx
import React from "react";
import Sample from "./Sample";

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      message: "最初のメッセージ"
    };

    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState({
      message: "ボタンが押されました"
    });
  }

  render() {
    return (
      <React.Fragment>
        <p>Hello world</p>
        <Sample num={"5"} />

        <p>{this.state.message}</p>
        <button onClick={this.handleClick}>ボタン</button>
      </React.Fragment>
    );
  }
}

export default App;
```
しかしこれではエラーになってしまいますね。
Propsのときと同様に、TypeScriptでは型の指定が必要です。
下記のように書き換えましょう。

```React:App.tsx
import React from "react";
import Sample from "./Sample";

interface Props {}

interface State {
  message: string;
}

class App extends React.Component<Props, State> {
  constructor(props: Props) {
    super(props);

    this.state = {
      message: "最初のメッセージ"
    };

    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState({
      message: "ボタンが押されました"
    });
  }

  render() {
    return (
      <React.Fragment>
        <p>Hello world</p>
        <Sample num={"5"} />

        <p>{this.state.message}</p>
        <button onClick={this.handleClick}>ボタン</button>
      </React.Fragment>
    );
  }
}

export default App;
```
これで問題なく画面が表示されました。

##参考
[TypeScriptチュートリアル① -環境構築編-](https://qiita.com/ochiochi/items/efdaa0ae7d8c972c8103)
[TypeScript チュートリアル](https://qiita.com/EBIHARA_kenji/items/31b7c1c62426bdabd263)
[React における State と Props の違い](https://qiita.com/kyrieleison/items/78b3295ff3f37969ab50)
[今からはじめるReact.js〜propsとstate、それからrefs〜](https://qiita.com/kuniken/items/a22adda392ccc30011b1)