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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With