You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
> As you can see we still return `undefined` from the reducer even though we use [immer](https://github.com/mweststrate/immer) and mutate our draft. Unfortunately, we can not omit `return` statement here due to [how TypeScript handles `void`](https://github.com/Microsoft/TypeScript/wiki/FAQ#why-are-functions-returning-non-void-assignable-to-function-returning-void). We can not even write `return` (withour `undefined`), because TypeScript then presumes the method returns `void`.
431
+
422
432
> You might have noticed a new import - `Immutable`. It's just a cool name for [DeepReadonly type](https://github.com/gcanti/typelevel-ts#deepreadonly). You don't have to use it. The example above would work just fine if used just `IReducerCatState`. Yet it's recommended to wrap it with `Immutable` to ensure that you never mutate it.
423
433
424
434
> Actually it makes total sense to use `Immutable` for state of regular reducers as well to make sure you never modify state directly.
425
435
436
+
## Reusing reducers
437
+
438
+
So what if we want to share some logic between reducers?
> You might have noticed that made this class generic. We have to do that because we do not know what actual state we going to extend, we can only put a constraint on it to make sure it satisfies the structure we need. In other words, if we used `IHungryState` directly and returned `{ hungry: true }` (not `{ ...state, hungry: true }`) from `hungry` compiler wouldn't complain.
470
+
471
+
> You don't have to use `ReducerClassMixin` class. It's nothing but a convenience wrapper to make sure your class carries an index signature for type-safety. Alternatively you can use `IReducerClassConstraint` interface and `ReducerClassMethod` type.
472
+
473
+
<details>
474
+
<summary>How to use `IReducerClassConstraint` interface and `ReducerClassMethod` type instead of `ReducerClassMixin` class</summary>
> @Extend can accept as many arguments as you want.
570
+
571
+
Now our cat reducer uses `wasteEnegry` to handle actions `ActionCatPlay`, `ActionCatBeAwesome`, `addEnergy` to handle `ActionCatEat` and inherits `hugry` and `full` methods to handle `ActionHungry` and `ActionFull` from `ReducerHungry`.
### When can we omit list of actions for `@Action`?
@@ -471,6 +765,10 @@ const res2 = reducer(res1, new ActionCatEat(5))
471
765
console.log(res2) // logs 135: 130 - previous value, 5 is added by addEnergy
472
766
```
473
767
768
+
### How @Extend works?
769
+
770
+
It iterates over its arguments and copies their methods and corresponding metadata to a prototype of our target reducer class.
771
+
474
772
## How does it compare to [ngrx-actions](https://github.com/amcdnl/ngrx-actions)?
475
773
476
774
1. Stricter typings. Now you'll never forget to add initial state, return a new state from your reducer and accidentally invoke `immer` as a result and etc.
0 commit comments