create-react-appを使うとReactの雛形を作ってくれるがTypeScriptには対応していないし,当面対応する予定もない。しかしforkしてTypeScriptの対応をしてくれたcreate-react-app-typescriptがある。これを使ってJavaScriptで作ったアプリをTypeScriptに書き直した。調べるのに苦労したので作業メモもかねてImmutableやReduxなどなどを使うアプリのサンプルを説明する。
以下のものを使う。JavaScriptによるReactアプリ作成・TypeScriptなどの要素技術は理解しているものとする。
- yarn
 - TypeScript-2.2.1
 - React
 - create-react-app
 - Immutable
 - Redux
 - material-ui
 
初期設定
$ yarn global add create-react-app
$ create-react-app demo-react-scripts-ts --scripts-version=react-scripts-ts
他に必要なものをインストール
$ yarn add immutable
$ yarn add material-ui @types/material-ui
$ yarn add redux
$ yarn add redux-actions @types/redux-actions
$ yarn add react-redux @types/react-redux
$ yarn add react-tap-event-plugin
App.tsxの開設
単純にボタンを押して数字を増やしたり減らしたりして表示する。
class Counter extends Record({counter: 0}) {
    counter: number;
    modify(diff: number) {
        return new Counter(this.set('counter', this.counter + diff));
    }
}
Immutableを使ってデータを保持するクラスを作成する。Record#setがMapに変わってしまうのでこういうやりかたになる。TypeScriptはJavaScriptより型がきちんとあっていいのだがimmutableなコレクションを使いにくい部分があるかなと思う。
interface AppProps {
    data: Counter;
    updateModel: (d: Counter) => void;
}
class App extends React.Component<AppProps, undefined> {
アプリのメインの記述。Component<any,any>としておけばなんでも通るがinterfaceを渡せばコンパイル時に変なpropsを書いてないかチェックできるようになる。2番目は`this.stateのinterfaceだがReduxを使うのでthis.stateを使うことはない。
    render() {
        return (
            <MuiThemeProvider>
                <div className="App">
                    <h1>{this.props.data.counter}</h1>
                    <FloatingActionButton onClick={() => this.props.updateModel(this.props.data.modify(1))}>
                        <ContentAdd/>
                    </FloatingActionButton>
FloatingActionButtonのonChangeの中身がモデルの更新作業となる。
                    <FloatingActionButton
                        secondary={true}
                        onClick={() => this.props.updateModel(this.props.data.modify(-1))}
                    >
                        <ContentRemove/>
                    </FloatingActionButton>
                </div>
            </MuiThemeProvider>
        );
    }
}
ここからReduxの記述になる。
const initialState = new Counter();
先程作ったモデルを初期値とする。
const updateModel = createAction<Counter>('UPDATE_MODEL');
redux-actionsで作るactionはモデルを更新するという一つだけで済む。実際のデータの更新はモデルクラスのメソッドを使う。
const reducer = handleActions<Counter>(
    {
        ['UPDATE_MODEL']: (state: Counter, action: Action<Counter>) => action.payload
    },
    initialState
);
更新作業も直感的な作業となる。
const store = createStore(reducer);
function mapStateToProps(state: Counter) {
    return {data: state};
}
function mapDispatchToProps(dispatch: Dispatch<Counter>) {
    return {
        updateModel: function (m: Counter) {
            dispatch(updateModel(m));
        }
    };
}
メソッドの型をきちんと入れなければならない。最初は型がわからなかった。
export default class RApp extends React.Component<undefined, undefined> {
    render() {
        const DApp = connect(mapStateToProps, mapDispatchToProps)(App);
        return (
            <Provider store={store}>
                <DApp />
            </Provider>);
    }
}
このようになる。
- https://github.com/takaki/demo-react-scripts-ts - githubに置いてあります