
2025.02.18
「売上をスケールする」AIの使い道とは アルペンが挑む、kintone×生成AIの接客データ活用法
typescript-fsaに頼らないReact×Redux(全1記事)
リンクをコピー
記事をブックマーク
甲斐田亮一氏:「typescript-fsaに頼らないReact × Redux」というタイトルで始めさせていただきます。僕は日本事務器という会社でフロントエンドエンジニア兼デザイナーをしている甲斐田といいます。
ふだんの業務で、React、TypeScriptでアプリケーションを書いています。
今回話すことですが、最近のTypeScript 2.8以降の機能を使って、React × Reduxの型付けを行っていきます。なるべくReact × Reduxのテンプレートのような書き方を崩さないように、型を組んでいきたいなと思います。
逆に、Flowやtypesctipt-fsaとの書き方や機能面での比較と、TypeScriptの詳しい型システムの解説は、今回行いません。なので、「最近のTypeScriptだとこういうふうに書けるんだよ」くらいの感じに思ってください。
最初にStateful Componentについて。
普通のクラスコンポーネントですよね。型はinterfaceかtype aliasを使ってPropsとStateをそれぞれ定義します。TypeScript3.0からdefaultPropsがサポートされていて、defaultPropsに定義したPropsであれば、宣言時に省略してもnullアサーションがされなくなっています。
型注釈をする場合は別途定義する必要があります。方法としてはこんな感じです。
まずtype aliasでPropsとStateを定義して、React.Componentのあとに型引数としてそれぞれ渡してあげます。InitialStateは別途宣言して、それをそのまま型宣言にも利用します。Readonlyを付けて、setState以外からのアクセスを禁止します。
これを見ていただいたらわかるんですが、リードオンリーって2つ出てきてますよね。これらはそれぞれ別のことをやっていて、上のReadonlyではstate.count=1という代入を、下のreadonlyではstate={count:1}という代入をそれぞれ禁止しています。
続いて、Stateless Functional Component。
React.SFCというもので型を付けていきます。defaultPropsを付ける際は、関数のデフォルト引数を利用して付けていきます。
先月のアップデートで追加されたReact.memoはまだ未対応です(注:発表当時。その後対応された。また、Stateless Functional Componentという名称はなくなり、Function Componentsという名称にまとめられた)。
プルリクは作成されていて、このプルリクで、今あれこれいろいろ議論されています。内容をざっと見たんですが、エキゾチックコンポーネントか、SpecialSFCというのが追加されていたので、このどちらかかなといった印象ですね(注:その後、NamedExoticComponentに決定)。
コードはこんな感じで、先ほどとあまり変わりはないんですが。
Propsを受け取る際に分割して、もし値がなければそれぞれ、これらの値を代入するよということをやっています。
ここからReduxの内容に入ってきます。まずはContainerです。ここでは2つのものに型を付けています。
まず1つ目がmapStateToPropsで、こちらは自分でアプリケーション内で使う必要な型を作成して、それを与えていきます。それで、mapDispatchToPropsは、ReduxにあるDispatchという型を使います。
アプリケーションで下側は定義されていて、ページが3つあります。それぞれcalcPage、hogePage、fooPageがあって、それをインポートしてmapStateToPropsのあとにStateを渡してあげる。mapDispatchToPropsのあとは、Dispatchを渡してあげます。このDispatchは、anyというタイププロパティを持つオブジェクトであれば、なんでも許容されるようになっています。
続いてAction。ここからがメインの話です。
typescript-fsaなりredux-actionsは専用の構文だったりaction creatorを作成していますが、素のTypeScriptだとActionのタイププロパティに「as typeof xxxx」で型を付けていきます。
こうすることで、actiontypeをただのstringではなくて、文字列リテラル型の型を付与することができます。コードはこんな感じになっていて、もとのテンプレートの書き方をほぼほぼ崩さずに書けているんじゃないのかなと思います。
そしてReducerで、先ほど作成したActionの型を紐づけていきます。
ここからがっつりTypeScriptの機能を使っていて、まずConditional typesのReturnTypeというものを使って、そのReducer内で受け取るActionを定義します。そして、Tagged union typesというもので各Actionが持つプロパティを絞り込みます。最後にnever型を使って、そのReducer内で受け取るActionの定義漏れだったり、タイポがないかをチェックします。
だいぶ小さくてすいません。そもそもこれは何してるかなんですけど、このReturnTypeは関数を受け取るようになっていて、その関数の戻り値の型を抽出するっていうことをやっています。
そして、それをunion typesで結合しています。
フォーカスしてみるとこのように、3つのActionが受け取ることをTypeScript側が認識することができています。
INCREMENT、DECREMENTはtypeだけを持っていて、CALCだったらpayloadを持っているとちゃんと認識しています。payloadは中身がnum1、num2を持っていて、それは型がnumberだということもちゃんと認識してくれています。
これをswitch文で、tagged union typesでActionの絞り込みを行っていきます。
そして、TypeScript側で「このActionだったらこの型を持っている」「payloadを持っている」と認識しているので、CALC内でpayloadに対して直接アクセスすることができています。
最後にnever型。
default部で定義して、もしこちらが予期していないActionが来た場合は、このnever型のアンダーバーの中にActionが流れ込みます。例えばこのDECREMENT定数をコメントアウトすると、例えばこのDECREMENTケースをコメントアウトすると、このReducerはINCREMENT、DECREMENT、CALCという3つのActionを期待しているのに、DECREMENTの受け取り口がなくなるので、DECREMENTがdefault区に流れ込みます。
そこでこのアンダーバーに、never型にアサインされてしまうので、TypeScriptがエラーを発動してしまう。なのでここで、その次が実行できなくなってしまいます。こうすることでReducerを型安全に、かつ型の恩恵を受け取りつつ書くことができます。
ただ、気を付けることがあります。
受け取るActionが1つのときは、このnever型が使えないんですよね。なのでnever型を消すか、普通にif文で書けば書けるようになります。JavaScriptだと、switch文に入る前にActionを分割代入で先に取ってから、switch文でpayloadのアクセスができるようになっていたんですが、それは今回の書き方ではできません。
最後、Middleware。
今回Middlewareは、素のMiddlewareで作りました。store、next、actionにそれぞれ型を付けます。actionの絞り込みには先ほどのConditional typesを利用できます。今回は書き方だけ紹介します。実際にアプリケーションで使うときは素のMiddlewareではなくて、sagaなりthunk、observablesを使うのがいいです。
コードとしてはこんなふうになっています。
storeにMiddlewareAPIというのを渡してあげて、Dispatchとそのアプリケーションで使うstoreを渡してあげます。ReduxはMiddlewareという型定義をちゃんと定義しているんですが、その場合はactionの型推論がanyになっているので。actionの型推論が一切なくなります。なので僕は書くとしたらこういうふうに書きます。
まとめです。
2.8以降の機能であれば素のTypeScriptでもいい感じに型を付けていけてるんじゃないのかなと思います。僕はもともとFlowを使っていて、TypeScriptって敬遠してたんですね。というのが、サードパーティを使わないといけないし、書き方が大きく崩れるなと思っていて、やってなかったんですが。
最近のTypeScriptだったらそのテンプレートを崩さずに、さらに型の恩恵にあやかりつつ書くことができるので、いいんじゃないのかなと思います。なのでFlowとかで迷っている人がいれば、TypeScriptを検討してみてもいいんじゃないのかなと思います。以上です、ご清聴ありがとうございました。
(会場拍手)
関連タグ:
2025.02.13
“最近の新人は報連相をしない”という、管理職の他責思考 部下に対する「NG指示」から見る、認識のズレを防ぐコツ
2025.02.13
AIを使いこなせない人が直面する本当の課題 元マッキンゼー・赤羽雄二氏が“英語の情報”を追い続ける理由
2025.02.06
すかいらーく創業者が、社長を辞めて75歳で再起業したわけ “あえて長居させるコーヒー店”の経営に込めるこだわり
2025.02.12
マネージャーは「プレイング3割」が適切 チームの業績を上げるためのマネジメントと業務の比率
2025.02.14
報連相ができない部下に対するコミュニケーションの取り方 「部下が悪い」で終わらせない、管理職のスキル向上のポイント
2025.02.13
上司からは丸投げ、部下からはハラスメント扱い、業務は増加…プレイングマネジャーを苦しめる「6つの圧力」とは
2025.02.12
何度言っても変わらない人への指示のポイント 相手が主体的に動き出す“お願い”の仕方
2025.02.13
「みんなで決めたから」を言い訳にして仲良しクラブで終わる組織 インパクトも多様性も両立させるソース原理
2025.02.10
32歳で「すかいらーく」を創業、75歳で「高倉町珈琲」で再起業 「失敗したからすかいらーくができた」横川竟氏流の経営哲学
2025.01.07
1月から始めたい「日記」を書く習慣 ビジネスパーソンにおすすめな3つの理由
2025.02.13
“最近の新人は報連相をしない”という、管理職の他責思考 部下に対する「NG指示」から見る、認識のズレを防ぐコツ
2025.02.13
AIを使いこなせない人が直面する本当の課題 元マッキンゼー・赤羽雄二氏が“英語の情報”を追い続ける理由
2025.02.06
すかいらーく創業者が、社長を辞めて75歳で再起業したわけ “あえて長居させるコーヒー店”の経営に込めるこだわり
2025.02.12
マネージャーは「プレイング3割」が適切 チームの業績を上げるためのマネジメントと業務の比率
2025.02.14
報連相ができない部下に対するコミュニケーションの取り方 「部下が悪い」で終わらせない、管理職のスキル向上のポイント
2025.02.13
上司からは丸投げ、部下からはハラスメント扱い、業務は増加…プレイングマネジャーを苦しめる「6つの圧力」とは
2025.02.12
何度言っても変わらない人への指示のポイント 相手が主体的に動き出す“お願い”の仕方
2025.02.13
「みんなで決めたから」を言い訳にして仲良しクラブで終わる組織 インパクトも多様性も両立させるソース原理
2025.02.10
32歳で「すかいらーく」を創業、75歳で「高倉町珈琲」で再起業 「失敗したからすかいらーくができた」横川竟氏流の経営哲学
2025.01.07
1月から始めたい「日記」を書く習慣 ビジネスパーソンにおすすめな3つの理由
着想から2か月でローンチ!爆速で新規事業を立ち上げる方法
2025.01.21 - 2025.01.21
新人の報連相スキルはマネージメントで引きあげろ!~管理職の「他責思考」を排除~
2025.01.29 - 2025.01.29
【手放すTALK LIVE#45】人と組織のポテンシャルが継承されるソース原理 ~人と組織のポテンシャルが花開く「ソース原理」とは~
2024.12.09 - 2024.12.09
『これで採用はうまくいく』著者が語る、今こそ採用担当に届けたい「口説く」力のすべて
2024.11.29 - 2024.11.29
第20回エクゼクティブメンターイベント「今、「ひと」と組織が共創する〜働き方の未来へ」
2024.12.07 - 2024.12.07