8

I am trying to get 2 selectors with the latest concatLatestFrom that was introduced in NgRx 12, however i cant seem to understand what i am doing wrong and i am unable to achieve this.

I have an effect that looks like this

  loadAllCases$ = createEffect(() => this._actions$.pipe(
    concatLatestFrom(() => [
      this.store.pipe(select(CaseSelectors.getAllCases)),
      this.store.pipe(select(CaseSelectors.getCasesLoaded))
    ]),
    navigation(this.caseLandingPage, {
      run: (snap, [loaded, cases]) => {
        if (loaded) {
          return CaseActions.loadAllSuccess();
        } else {
          return this._caseService.getAll().pipe(
            map(cases => CaseActions.loadAllSuccess(cases))
          );
        }
      },
      onError: (action, error) => {
        return CaseActions.loadAllFailed(error);
      }
    })
  ));

However this doesnt seem to work due to type incompatibility

Argument of type 'OperatorFunction<Action, [Action, boolean, Case[]]>' is not assignable to 
parameter of type 'OperatorFunction<Action, ActionOrActionWithState<unknown, Action>>'. 
Type '[Action, boolean, Case[]]' is not assignable to type 'ActionOrActionWithState<unknown,
Action>'.
Type '[Action, boolean, Case[]]' is not assignable to type '[Action, unknown]'.       
Source has 3 element(s) but target allows only 2

However. if i just leave one selector this works fine, is this a case that using concatLatestFrom can only select one selector? Note i have tried chaining them one after the other this produces the same error. Any help or advice appretiated.

Update

This appears to be Nx specific bug, and the navigation pipe it providers, i have oppened a bug related issue with the Nx Repository https://github.com/nrwl/nx/issues/6830

The code in the example works fine if it is piped with any RxJs operation.

Harry
  • 3,333
  • 3
  • 18
  • 28

3 Answers3

11

There is a type declaration for the concatLatestFrom function and its overloaded version

import { Observable, ObservedValueOf, OperatorFunction } from 'rxjs';
export declare function concatLatestFrom<T extends Observable<unknown>[], V>(observablesFactory: (value: V) => [...T]): OperatorFunction<V, [V, ...{
    [i in keyof T]: ObservedValueOf<T[i]>;
}]>;
export declare function concatLatestFrom<T extends Observable<unknown>, V>(observableFactory: (value: V) => T): OperatorFunction<V, [V, ObservedValueOf<T>]>;

https://github.com/ngrx/platform/blob/12.4.0/modules/effects/src/concat_latest_from.ts

So you're right this function accepts either a single observable or an array of observables.

But it seems you're using order of operators in a wrong way

I'm not sure what does navigation and caseLandingPage mean, but this example might give you an idea of how to fix/improve your effect handler

public readonly something$ = createEffect(
    () =>
      this.actions$.pipe(
        ofType(someAction),
        concatLatestFrom(() => [
          this.store.select(selectFoo),
          this.store.select(selectBar),
        ]),
        switchMap(([action, foo, bar]) => {

          // Do what you need

        }),
      ),
  );
Anton Kochev
  • 300
  • 1
  • 3
  • 13
  • Hi Anthon apologies i forgot to update that this is an Nx issue with the navigation pipe rather than with rxjs. The format i have in my question works fine if its piped with any rxjs operators. I will update that a bug reported has been oppened with the nx library – Harry Sep 15 '21 at 09:56
1

Hmmmm, the types accept an array of selectors and there's also a test to verify that it works.

Do you have a runnable reproduction? The problem will probably be something else.

The error itself mentions the correct types returned by concatLatestFrom, so my guess would be that the navigate operator needs to be tweaked.

Type '[Action, boolean, Case[]]' is not assignable ...
timdeschryver
  • 14,415
  • 1
  • 19
  • 32
  • I hve decided to upvote this but not sure if it should be marked as correct, this works if i use map that is true so it is an issue with navigate thus making this answer correct. However i would like to leave this open in case someone has a workaround, – Harry Aug 24 '21 at 01:06
0

I don't think you need the pipe functions, like this:

   concatLatestFrom(() => [
      this.store.select(CaseSelectors.getAllCases),
      this.store.select(CaseSelectors.getCasesLoaded)
    ]),
Michiel
  • 4,160
  • 3
  • 30
  • 42