Actionのunion型

action は「起きたこと」の書類

前のレッスンの action は "increase" という文字だけでした。カートではそうはいきません。「どの商品を入れるのか」「どの行を外すのか」「いくつに変えるのか」という中身が要ります。

そこで action をオブジェクトにします。何が起きたかを type に書き、必要な材料を一緒に載せます。

dispatch({ type: "ADD", item }); dispatch({ type: "REMOVE", id: "1" }); dispatch({ type: "CHANGE_QTY", id: "1", qty: 3 });

操作の一覧をユニオン型で書く

3つの action は、載せている材料がそれぞれ違います。ADD には商品そのものが要りますが、REMOVE に要るのは id だけです。これを1つの型で表すのがユニオン型です。TypeScript入門でやった「どれか1つ」の型が、ここで効いてきます。

type CartAction = | { type: "ADD"; item: Item } | { type: "REMOVE"; id: string } | { type: "CHANGE_QTY"; id: string; qty: number };

読み方は「CartAction はこの3つのどれか」です。この型が付いていれば、dispatch({ type: "REMOVE" }) のように id を忘れた呼び出しは、その場で怒られます。カートにできることの一覧が、型として1か所に書いてある状態になりました。

switch を書くと絞り込まれる

いいことがもう1つあります。reducer の中で action.type を switch にかけると、TypeScript は case ごとに「これはこの形の action だ」と絞り込みます。

case "ADD": return [...cart, { item: action.item, qty: 1 }]; case "REMOVE": return cart.filter((line) => line.item.id !== action.id);

ADD の中では action.item が読めて、action.id は無いと言われます。REMOVE の中では逆です。これを絞り込みと呼びます。書ける場所でしか書けないので、材料の取り違えが起きません。

type に string を使うと、この絞り込みは働きません。どの case でも中身が分からないままになり、型を書いた意味がほとんど消えます。

演習

CartAction を3つのユニオン型にして、削除と数量変更の dispatch を書きます。

ヒント

App.tsx
App.tsx
プレビュー

できているか

  • スニーカーを入れると合計が 4800 円になる
  • 革靴も入れると2行になり合計が 14600 円になる
  • スニーカーの +1 で数量が2、合計が 19400 円になる
  • スニーカーを削除すると革靴だけが残る