0
votes

So I have a product search effect. Basically I first dispatch a search_start action, which has a payload of parameters for that search, The effect takes that then goes to a service and I get that response back, which gives me a list of products. I want to be able to then do two things:

  1. Dispatch a successful action with the collection of products
  2. Save the parameters for that search to be used later for 'search history' which is currently in the 'action.payload'

I'm having a problem the 2nd piece mainly because doing switchMap and having a returnType of 'SearchResultResponseType' means that I can't now do a SearchSave(action.payload) mainly because the payload has the type of 'SearchParameterType'. So I can only execute my SearchSuccess action.

Is there anyway this can be accomplished? I tried changing the response type to a super type that takes both SearchParameterType and SearchResultResponseType as two properties on that type and having my productSearchService return that instead but that seemed to yield errors as well. Isn't there a simper way?

       export class ProductSearchEffects {
          @Effect() startSearch$: Observable<
            ActionWithPayload<SearchResultResponseType> | Observable<Action>
          > = this.actions$.pipe(
            ofType<SearchStart>(ProductSearchActions.SEARCH_START),
            mergeMap(action =>
              this.productSearchService.fetchSearchResults(action.payload)
                .pipe(
// if successful then save search and dispatch search success
                switchMap((data: SearchResultResponseType) => [
                    new SearchSave(action.payload),
                    new SearchSuccess(data),
                  ]),

                  catchError(() => of(new SearchFail())),
                ),
            ),
          );
2

2 Answers

1
votes

The common practice I've seen and personally adopted is to alias your actions, i.e., type SearchAction = SearchStart | SearchSave | SearchSuccess | SearchFail' and then the return type of your effect is Observable<SearchAction>. TypeScript will then verify that all actions being returned are covered by the alias.

2
votes

I don't think you need to explicitly define the return type. You can do it with mergeMap otherwise. I see you put your switchMap and mergeMap in reverse, you just need to reverse the position and you should be good to go.

export class ProductSearchEffects {
          @Effect() startSearch$ = this.actions$.pipe(
            ofType<SearchStart>(ProductSearchActions.SEARCH_START),
            switchMap(action =>
              this.productSearchService.fetchSearchResults(action.payload)
                .pipe(
                  mergeMap((data: SearchResultResponseType) => [
                    new SearchSave(action.payload),
                    new SearchSuccess(data),
                  ]),
                  catchError(() => of(new SearchFail())),
                ),
            ),
          );