Vincent
Vincent

Reputation: 1304

Type safe Effects for the Actions passed from createAction method in ngrx 11+

After reading several blogs details the usage and benefits of using createAction/createEffect (compare to classic @Effect and implements Action) which enables IDE to imply typing from the createAction method without declaring types again.

But what if we need to explicitly declare e.g. while combining other observables before pipe down to the stream?

For example (for full createEffect, see below),

this.actions$.pipe(ofType(FooActions.getFoo)).pipe(
      withLatestFrom(bar$),
      map(
        ([foo, bar]: [
          ReturnType<typeof FooActions.getFoo>,
          Bar[]
        ]) => {
          ...
          return FooActions.loadFoo(...);
        }
      )
    );

Example above shows the need of explicitly declare the type of getFoo action. Since when adding the second observable bar$ (implementation omitted) to the tuple sometimes we need to know the type of bar for convenience of programming.

Now, the typing of first item down the pipe couldn't be omitted, but how we are able to declare it? Is my code correct to copy the action creation function name and adding typeof, then wrapped by a ReturnType? (ReturnType<typeof FooActions.getFoo>)

It looks chunky and anti-pattern at a glance in this way.

Further thinking is, how we declare the created Effect type (onLoadFooBar$)?

const onLoadFooBar$ = createEffect(() => {
    return this.actions$.pipe(ofType(FooActions.getFoo)).pipe(
      withLatestFrom(bar$),
      map(
        ([foo, bar]: [
          ReturnType<typeof FooActions.getFoo>,
          Bar[]
        ]) => {
          ...
          return FooActions.loadFoo(...);
        }
      )
    );
});

Is it to be onLoadFooBar$: ReturnType<typeof FooActions.loadFoo> = createEffect(() => {

I found the union method wrapped the ReturnType but it is expanded to cover more than the typing I need at this place.

Upvotes: 0

Views: 328

Answers (1)

timdeschryver
timdeschryver

Reputation: 15507

Manually adding types shouldn't be needed. Even if you add other observables to the mix. If you have a reproduction, I'm happy to take a look.

Side note: try concatLatestFrom instead of withLatestFrom: https://github.com/timdeschryver/eslint-plugin-ngrx/blob/main/docs/rules/prefer-concat-latest-from.md

Upvotes: 1

Related Questions