LoginSignup
440

More than 3 years have passed since last update.

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

Last updated at Posted at 2016-03-15

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

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

はじめに

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

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

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

追加で使うツール類

なし

今なら以下で試せます。

具体的変更点

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

始める前の変更点

まず ここを開きます。

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

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

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

npx create-react-app my-app --typescript 

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

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

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

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

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

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

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

interface SquareProps {
    value: number;
}


class Square extends React.Component<SquareProps> {

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

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

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

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

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

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

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安全な言語になります

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

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

 <button className="square" onClick={() => this.setState({value: 'X'})}>

とかけって言ってきますが、、、、、コンパイルエラーになりますね。
なんでかというと先程のSquareStatevalueの定義を思い出して下さい。

interface SquareState {
  value: number | null;
}

文字列が許容しない設定になっていました。 素晴らしいです。
変更しましょう

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

動くようになりました。

Developer Tools

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

State のリフトアップ

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


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ではコンパイルエラーになるので挙動を確認することなく問題があることが解ります。
BoardhandleClickを設定してエラーが消えることを確認して下さい

この時点での SquareProps

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

関数コンポーネント

TypeScriptにおける変更点は

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

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

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

手番の処理

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

残り

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

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

感想

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

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

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
440