Nadhem
Nadhem

Reputation: 38

Problem setting up Redux with TypeScript when having multiple action payload types

I'm trying to set up redux with typescript in a react app and I don't understand what am I doing wrong. Here are my types and action creators.

export type FetchFamilyListError = {
  type: typeof FETCH_FAMILY_LIST_ERROR;
  payload: string;
};

export type FetchFamilyListSuccess = {
  type: typeof FETCH_FAMILY_LIST_SUCCESS;
  payload: Family[];
};

export type FamilyActions = FetchFamilyListError | FetchFamilyListSuccess;

export const fetchFamilyListError = (error: string): types.FamilyActions => ({
  type: types.FETCH_FAMILY_LIST_ERROR,
  payload: error
});

export const fetchFamilyListSuccess = (
  families: Family[]
): types.FamilyActions => ({
  type: types.FETCH_FAMILY_LIST_SUCCESS,
  payload: families
});

And here is the reducer.

export type familyState = {
  families: Family[];
  filters: {
    size: number;
  };
  error: string | null;
};

const initialState: familyState = {
  families: [],
  filters: {
    size: 0
  },
  error: null
};

const familyReducer = (
  state = initialState,
  action: types.FamilyActions
): familyState => {
  const actions = {
    [types.FETCH_FAMILY_LIST_ERROR]: () =>
      produce(state, draftState => {
        draftState.error = action.payload; // <--- error here
      }),
    [types.FETCH_FAMILY_LIST_SUCCESS]: () => ({
      families: [],
      filters: {
        size: 0
      },
      error: null
    }),
    default: () => state
  };
  return actions[action.type] ? actions[action.type]() : actions.default();
};

I'm getting Type 'string | Family[]' is not assignable to type 'string | null'. Type 'Family[]' is not assignable to type 'string' I guess this is because action.payload can either be a string or Family[], how can I fix this?

Right now I'm doing this

draftState.error =
          typeof action.payload === "string" ? action.payload : null;

But it doesn't seem like the right way to do this.

Upvotes: 1

Views: 1393

Answers (1)

James
James

Reputation: 82096

I guess this is because action.payload can either be a string or Family[]

Correct, the issue is in your reducer, action is defined as types.FamilyActions, so when you attempt to set draftState.error there is ambiguity because TS can't determine which action it is dealing with.

Given we know which one it will be based on the action type, you can just cast the payload to the appropriate type e.g.

draftState.error = action.payload as string

Upvotes: 4

Related Questions