Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@ngrx actions with multiple payloads

I am creating a web app using Angular 4 and @ngrx 4 and I am having a problem configuring strong typed actions.

I am new to @ngrx and I created the following class for my actions:

export const ActionTypes = {
  LOAD_PRODUCT_TREE: 'load-product-tree',
  LOAD_PRODUCT_TREE_COMPLETE: 'load-product-tree-complete'
};

// Load product tree by Id.
export class LoadProductTreeAction implements Action {
  type = ActionTypes.LOAD_PRODUCT_TREE;
  constructor (public payload: number) { }
}

export class LoadProductTreeCompleteAction implements Action {
  type = ActionTypes.LOAD_PRODUCT_TREE_COMPLETE;
  constructor (public payload: Map<number, Node>) { }
}

export type Actions = LoadProductTreeAction | LoadProductTreeCompleteAction;

However when I try to use these actions in my reducer:

export interface State {
  productTree: Map<number, Node>;
}

const initialState: State = {
  productTree: new Map<number, Node>()
};

export function productTreeReducer(state = initialState, action: productTreeOperations.Actions): State {

  switch (action.type) {
    case productTreeOperations.ActionTypes.LOAD_PRODUCT_TREE:
      return state;

    case productTreeOperations.ActionTypes.LOAD_PRODUCT_TREE_COMPLETE:
      return { productTree: action.payload };

    default:
      return state;
  }

}

I get this error: Type '{ productTree: number | Map<number, Node>; }' is not assignable to type 'State'. Types of property 'productTree' are incompatible. Type 'number | Map<number, Node>' is not assignable to type 'Map<number, Node>'. Type 'number' is not assignable to type 'Map<number, Node>'. in this line: return { productTree: action.payload };

How can I create a set of actions that take different payloads / arguments?

Also what would be the best practice for the return value of the LOAD_PRODUCT_TREE action in the reducer? Should I return the current state while the information is being loaded from the backend, or should I return something else?

like image 643
Felipe Avatar asked Sep 15 '25 17:09

Felipe


1 Answers

Assuming that you are using the default Action interface of the framework, do the following refactor:

export const LOAD_PRODUCT_TREE = 'load-product-tree';
export const LOAD_PRODUCT_TREE_COMPLETE = 'load-product-tree-complete';

export class LoadProductTreeAction implements Action {
  readonly type = LOAD_PRODUCT_TREE;
  constructor (public payload: number) { }
}

export class LoadProductTreeCompleteAction implements Action {
  readonly type = LOAD_PRODUCT_TREE_COMPLETE;
  constructor (public payload: Map<number, Node>) { }
}

export type Actions = LoadProductTreeAction | LoadProductTreeCompleteAction;

export function productTreeReducer(state = initialState, action: productTreeOperations.Actions): State {

  switch (action.type) {
    case productTreeOperations.LOAD_PRODUCT_TREE:
      return state;

    case productTreeOperations.LOAD_PRODUCT_TREE_COMPLETE:
      return { productTree: action.payload };

    default:
      return state;
  }
}

I will later add the corresponding explanations, but basically you want typescript to recognize the type property as an individual type, and not as a string.

like image 80
Jota.Toledo Avatar answered Sep 18 '25 08:09

Jota.Toledo