TypeScriptを使ってReactのチュートリアルを進めると捗るかなと思った(実際捗る)


この記事を書いたのは2016年のことでした。それから２年。
いつの間にか日本語チュートリアルが消えたし、結構未だにいいねを押してくださるので更新することにしました。(2018/2/2) 

reactの本家ドキュメントが日本語化されたため更新します。
(2019/4/11)

# はじめに

タイトルみたいなことを考えていました。
実際補完が効くのはかなり有効でしたが、チュートリアル通りにいかない点が多々出ました。 **結局色んな所を見るはめになりました**

でも総合してTypeScriptに向いているフレームワークだと思ったので詰まったところと解決方法を纏めてみることにしました

TypeScript自体も学習コストが凄く低くて(ES2015 + 型)素敵だったのでいいと思いました。

# 追加で使うツール類

なし

今なら以下で試せます。

* **stackblitz** [オンライン版VisualStudioCode的な(コード補完が効きます)](https://stackblitz.com/edit/react-ts-tutorial-starter)



# 具体的変更点

https://ja.reactjs.org/tutorial/tutorial.html
上記を見ながら作業を進めます。



## 始める前の変更点

まず [ここ](https://stackblitz.com/edit/react-ts-tutorial-starter)を開きます。


"Fork" ボタンを押して作業できるようにしましょう
それだけです。すごくはかどります。

チュートリアルでは``create-react-app`` でローカルで開発する方法も書いています。
これについてもTypeScriptで同じことはできます。

コマンドとして以下を使うだけです。

```sh
npx create-react-app my-app --typescript 
```




## チュートリアルの入門から

https://ja.reactjs.org/tutorial/tutorial.html#what-is-react
とりあえず "Reactとは何か？"を読み終わりましたよね。

JSXのような拡張はTypeScriptにもあり、その場合の拡張子も `.tsx` となります。


## Propsを通してデータを渡す。

https://ja.reactjs.org/tutorial/tutorial.html#passing-data-through-props

ただのJSに於いては、Propsはただのオブジェクトでスキーマレスですが、
TypeScriptではスキーマ設定可能で**補完**できるようになります。

でもエディターで補完を聞かせても今はpropsの中味が``children``くらいしかありませんよね。


以下の様な感じで定義します。

```ts
interface SquareProps {
    value: number;
}


class Square extends React.Component<SquareProps> {

```



<!-- (因みに既存TypeScriptユーザ向けの話ですが ``Rect.Props<T>`` を使うのは非推奨らしいです。 これ書くまで気づかんかった。) -->

チュートリアルに従い ``/* TODO */`` の箇所を 置き換えてみて下さい

上記のようにPropsを作ると補完が効いて ``/*TODO*/`` の箇所に入れる ``this.props.value`` が簡単に入ることが解りますか？

更に自動的に、``<Board/>`` 内で使用中の ``<Square/>`` パラメータ(この場合は``value``)が足りないとエラーを吐いてくれます。特に序盤は何が足りないのかわからないので凄く楽ちんになります。


## インタラクティブなコンポーネントをつくる

https://ja.reactjs.org/tutorial/tutorial.html#making-an-interactive-component

お分かりでしょうか?
チュートリアルのように ``onClick={alert('click')}``なんぞ書くと``TypeScript``は怒ってくださいます。


今度は``<Square/>``に``state`` をもたせる話なので、同じように``interface``を作ります

```diff
interface SquareProps {
    value: number;
}

+interface SquareState {
+  value: number | null;
+}

-class Square extends React.Component<SquareProps> {
+class Square extends React.Component<SquareProps, SquareState> {

```

``number | null`` は 数値型かnullだよって意味です。 TypeScriptは設定によって[null安全](https://qiita.com/koher/items/e4835bd429b88809ab33)な言語になります

今度はコンストラクタで``state``に``value``を設定していないとエラーになることが分かるでしょうか？

さてチュートリアル通りに進めると

```tsx
 <button className="square" onClick={() => this.setState({value: 'X'})}>
```
とかけって言ってきますが、、、、、コンパイルエラーになりますね。
なんでかというと先程の``SquareState``の ``value``の定義を思い出して下さい。

```ts
interface SquareState {
  value: number | null;
}
```
文字列が許容しない設定になっていました。 素晴らしいです。
変更しましょう

```diff
interface SquareState {
-  value: number | null;
+  value: string | null;
}
```
動くようになりました。

## Developer Tools
https://ja.reactjs.org/tutorial/tutorial.html#developer-tools

``CodePen`` と違って**stackblitz** はInspectは簡単です。
右上の``Open in New Window`` で別ウインドウで動作確認ができるのでそこで``Inspect``を使うだけです。


## State のリフトアップ
https://ja.reactjs.org/tutorial/tutorial.html#lifting-state-up

親コンポーネントである ``<Board />`` にstateをもたせる(つまり Lifting State Up)ってことみたいですね。
``SquareState`` はいらない子みたいなので削除します。
そしてBoard側にStateを持たせます。 
(より上位のコンポーネントにStateを集めるという考えが最終的に``Redux``につながっていくんですよねぇ。)

```ts

type SquareType = string | null;


interface SquareProps {
  value: SquareType;
}


/* 省略 */
interface BoardState {
  squares:SquareType[]
}
class Board extends React.Component<any, BoardState> {
  constructor(props) {
    super(props)
    this.state = {
      squares: Array<SquareType>(9).fill(null)
    }
  }
....
```

``SquareType = string | null `` として型定義をまとめてみました。

チュートリアルの記述を見てみると

``
まだBoard上でhandleClick()メソッドを定義していないので、コードがクラッシュします。
``

とありますがそもそもTypeScriptではコンパイルエラーになるので挙動を確認することなく問題があることが解ります。
``Board`` に``  handleClick``を設定してエラーが消えることを確認して下さい

この時点での SquareProps 

```ts
interface SquareProps {
  value: SquareType;
  onClick: () => void;
}
```

## 関数コンポーネント
https://ja.reactjs.org/tutorial/tutorial.html#function-components

TypeScriptにおける変更点は

```tsx
function Square(props: SquareProps) {
  return (
    <button className="square" onClick={props.onClick}>
      {props.value}
    </button>
  );
}
```

props の型を明示するだけです。

``onClick={props.onClick()}`` と書くと、コンパイルエラーになります。


## 手番の処理
https://ja.reactjs.org/tutorial/tutorial.html#taking-turns

もうここまで来たら、わかると思います。 ``BaordState`` には``xIsNext:boolean `` の追加が必要ってことですね。

## 残り

あとは特に語ることもないです。
チュートリアルを進めて下さい。

最終的な結果は以下に置いておきます。

https://stackblitz.com/edit/react-ts-tutorial-starter-rapwmd


# 感想

JSX(TSX)とTypeScriptの相性最高だと思いました。
コンパイラがカスタムエレメントをまるでもとからあるHTMLタグかのように
リアルタイムに指摘してくれるさまは至福のひとときです。

今は仕事で主にVue.jsばかり触っていますが、ぜひ仕事でも使ってみたいものです。