Home > Blockchain >  overloading payload in useReducer hook, TypeScript
overloading payload in useReducer hook, TypeScript

Time:09-30

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
}
  • Related