はじめに
TypeScript + React HooksのuseReducerで、オブジェクトの配列のstateを作成したとき、
dispatch関数がtypeの値に応じて必要な引数だけを要求するようにしたくなった
つまり、reducerの引数であるactionが、
typeの値に対応したpayloadを持つように型定義したい
方法
型定義において、typeをtype: string;
ではなく具体値で定義する
interface AddAction {
type: 'add',
payload: {
id: number;
a: number;
b: string;
}
}
interface RemoveAction {
type: 'remove',
payload: {
id: number;
}
}
定義したそれぞれの型を |
でつなぐ
const reducer = (
state: Array<MyDataType>,
action: AddAction | RemoveAction,
) => {
if (action.type === 'add') {
// addの処理
} else if (action.type === 'remove') {
// removeの処理
}
}
実装例
- オブジェクトの配列であるstateについての実装例
-
users
:ユーザ情報(id, name, age)を管理するオブジェクトの配列のstate - 新たにユーザ情報を追加する
add
と、idをもとにageを更新するupdateAge
を実装
sample.tsx
import React, { useReducer } from 'react';
interface User {
id: number;
name: string;
age: number;
gender: string;
}
interface AddAction {
type: 'add';
payload: User;
}
interface UpdateAgeAction {
type: 'updateAge';
payload: {
id: number;
age: number;
};
}
export const reducer = (
state: Array<User>,
action: AddAction | UpdateAgeAction
): Array<User> => {
if (action.type === 'add') {
// addの処理
} else if (action.type === 'updateAge') {
// ageの更新処理
}
}
const MyComponent: React.FC = () => {
const [users, usersDispatch] = useReducer(reducer, []);
const addUser = (newUser: User) => {
usersDispatch({
type: 'add',
payload: newUser,
}
}
const updateAge = (userId: number, newAge: number) => {
usersDispatch({
type: 'updateAge',
payload: {
id: userId,
age: newAge,
}
}
}
// 以下省略
}