Here is my useReducer hook initialized in Function Component. In listReducer
function I want to create user ==> I assign to state an array of type User. So, in payload I have to have User[]
. But, when I delete ==> only single element of them by _id (had to settle with using private variable), I have to pass string type to payload.
type State = {
list: User[];
}
const initialListState: State = {
list: [],
};
enum ActionKind {
CREATE = 'CREATE',
DELETE = 'DELETE',
}
type Action = {
type: ActionKind,
payload: User[] | string;
}
function listReducer(state: State, action: Action): State {
const { type, payload } = action;
switch (type) {
case ActionKind.CREATE:
return { list: action.payload };
case ActionKind.DELETE:
return {
list: state.list.filter((el) => el._id !== action.payload._id),
};
default:
return state;
}
}
export const DashBoard = () => {
const [state, dispatch] = useReducer(listReducer, initialListState);
useEffect(() => {
if (allUsers && allUsers.length > 0) {
dispatch({ type: ActionKind.CREATE,
payload: allUsers,
});
}
}, [allUsers]);
in useEffect , when allUsers(type User[]) is assigned to array, I'm passing allUsers to payload.
Here is error that I have at current code: TS2339: Property 'list' does not exist on type 'string | User[]'.
Here is User interface
export interface User {
_id: string;
name: string;
age: string;
email: string;
password: string;
isAdmin: boolean;
}
I tried to make payload as object with separate properties for id
-string and list
-User[]
type Action = {
type: ActionKind,
payload: {
list: User[],
id: string,
},
}
function listReducer(state: State, action: Action): State {
const { type, payload } = action;
switch (type) {
case ActionKind.CREATE:
return { list: action.payload.list };
...
and inside useEffect
dispatch({ type: ActionKind.CREATE,
payload: {
list: allUsers,
},
});
but this way payload.list and payload.id are required fields - multiple errors if type declaration I make them optional like ==>
type Action = {
type: ActionKind,
payload: {
list?: User[],
id?: string,
},
}
then list
is User[] | undefined
and id
is string | undefined
How do I make it right? will be glad for any help
CodePudding user response:
I like to implement reducer like in react with typescript as follows:
type State = {
x: number
y: string
z: Array<string>
}
type Payload1 = {
x: number
y: string
}
type Payload2 = {
z: Array<string>
}
type Action
= { type: "action1"; payload: Payload1 }
| { type: "action2"; payload: Payload2 }
function reducer(state: State, action: Action): State {
switch (action.type) {
case "action1":
return { ...state, x: action.payload.x, y: action.payload.y }
case "action2":
return { ...state, z: action.payload.z }
}
throw new Error("unreachable");
}
And all works fine. Then you can take this as reference and create something like:
type Action = {
type: ActionType.CREATE
payload: User[]
} | {
type: ActionType.DELETE
payload: number
}