この記事を書いたのは2016年のことでした。それから2年。
いつの間にか日本語チュートリアルが消えたし、結構未だにいいねを押してくださるので更新することにしました。(2018/2/2)
reactの本家ドキュメントが日本語化されたため更新します。
(2019/4/11)
はじめに
タイトルみたいなことを考えていました。
実際補完が効くのはかなり有効でしたが、チュートリアル通りにいかない点が多々出ました。 結局色んな所を見るはめになりました
でも総合してTypeScriptに向いているフレームワークだと思ったので詰まったところと解決方法を纏めてみることにしました
TypeScript自体も学習コストが凄く低くて(ES2015 + 型)素敵だったのでいいと思いました。
追加で使うツール類
なし
今なら以下で試せます。
- stackblitz オンライン版VisualStudioCode的な(コード補完が効きます)
具体的変更点
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安全な言語になります
今度はコンストラクタでstate
にvalue
を設定していないとエラーになることが分かるでしょうか?
さてチュートリアル通りに進めると
<button className="square" onClick={() => this.setState({value: 'X'})}>
とかけって言ってきますが、、、、、コンパイルエラーになりますね。
なんでかというと先程のSquareState
の value
の定義を思い出して下さい。
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ではコンパイルエラーになるので挙動を確認することなく問題があることが解ります。
Board
に handleClick
を設定してエラーが消えることを確認して下さい
この時点での 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ばかり触っていますが、ぜひ仕事でも使ってみたいものです。