Skip to content

Commit

Permalink
fix: update with changes from v2.5.0 release
Browse files Browse the repository at this point in the history
  • Loading branch information
sseppola committed May 18, 2023
1 parent f8c1a59 commit 9531ca0
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 145 deletions.
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ export {

export {
reducer,
actionReducer,
streamReducer,
combineReducers,
Reducer,
RegisteredReducer,
Expand Down
6 changes: 6 additions & 0 deletions src/internal/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ export interface ActionCreatorCommon {
*
* This type allows for inferring overlap of the payload type between multiple
* action creators with different payloads.
*
* @deprecated
* v2.6.0 Use ActionCreator type instead
*/
export interface UnknownActionCreatorWithPayload<Payload>
extends ActionCreatorCommon {
Expand All @@ -34,6 +37,9 @@ export interface UnknownActionCreatorWithPayload<Payload>
* This type has payload as an optional argument to the action creator function
* and has return type `UnknownAction`. It's useful when you need to define a
* generic action creator that might create actions with or without actions.
*
* @deprecated
* v2.6.0 Use ActionCreator type instead
*/
export interface UnknownActionCreator extends ActionCreatorCommon {
(payload?: any): UnknownAction;
Expand Down
2 changes: 1 addition & 1 deletion src/reducer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { incrementMocks } from './internal/testing/mock';
const { reducers, actionCreators, handlers } = incrementMocks;
const { actions, words, numbers, errors } = incrementMocks.marbles;
const reducerArray = Object.values(reducers);
const alwaysReset = reducer(
const alwaysReset = reducer<number, any>(
[
actionCreators.incrementOne,
actionCreators.incrementMany,
Expand Down
203 changes: 59 additions & 144 deletions src/reducer.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {
InteropObservable,
Observable,
ObservableInput,
OperatorFunction,
Expand All @@ -8,12 +7,8 @@ import {
pipe,
} from 'rxjs';
import { filter, map, mergeWith, scan } from 'rxjs/operators';
import {
UnknownAction,
UnknownActionCreator,
UnknownActionCreatorWithPayload,
VoidPayload,
} from './internal/types';
import type { UnknownAction, VoidPayload } from './internal/types';
import type { ActionCreator } from './types/ActionCreator';
import { defaultErrorSubject } from './internal/defaultErrorSubject';
import { ofType } from './operators/operators';
import { isObservableInput } from './isObservableInput';
Expand All @@ -29,7 +24,7 @@ export type Reducer<State, Payload = VoidPayload> = (

type RegisteredActionReducer<State, Payload = any> = Reducer<State, Payload> & {
trigger: {
actions: UnknownActionCreator[];
actions: ActionCreator<Payload>[];
};
};
type RegisteredStreamReducer<State, Payload = any> = Reducer<State, Payload> & {
Expand All @@ -43,12 +38,8 @@ export type RegisteredReducer<State, Payload = any> = Reducer<
Payload
> & {
trigger:
| {
actions: UnknownActionCreator[];
}
| {
source$: Observable<Payload>;
};
| { actions: ActionCreator<Payload>[] }
| { source$: Observable<Payload> };
};

const isActionReducer = <State, Payload>(
Expand All @@ -61,128 +52,44 @@ const isStreamReducer = <State, Payload>(
): reducerFn is RegisteredStreamReducer<State, Payload> =>
'source$' in reducerFn.trigger;

type StreamReducerCreator = {
/**
* Define a reducer for a stream
*
* @see combineReducers
* @param source$ The stream which will trigger this reducer
* @param reducer The reducer function
* @template `State` - The state the reducer reduces to
* @template `Payload` - The type of values `source$` emits
* @returns A registered reducer that can be passed into `combineReducers`, or
* called directly as if it was the `reducer` parameter itself.
*/
<State, Payload>(
source$: ObservableInput<Payload>,
reducer: Reducer<State, Payload>
): RegisteredReducer<State, Payload>;
};

type ActionReducerCreator = {
/**
* Define a reducer for multiple actions with overlapping payload
*
* @see combineReducers
* @param actionCreator The action creator to assign this reducer to and
* extract payload type from
* @param reducer The reducer function
* @template `State` - The state the reducer reduces to
* @template `Payload` - The payload of the action, fed to the reducer together
* with the state. Should be automatically extracted from
* the `actionCreator` parameter
* @returns A registered reducer that can be passed into `combineReducers`, or
* called directly as if it was the `reducer` parameter itself.
*/
<State, Payload>(
actionCreator: UnknownActionCreatorWithPayload<Payload>[],
reducer: Reducer<State, Payload>
): RegisteredReducer<State, Payload>;

/**
* Define a reducer for multiple actions without overlapping payload
*
* @see combineReducers
* @param actionCreator The action creator to assign this reducer to and
* extract payload type from
* @param reducer The reducer function
* @template `State` - The state the reducer reduces to
* @returns A registered reducer that can be passed into `combineReducers`, or
* called directly as if it was the `reducer` parameter itself.
*/
<State>(
actionCreator: UnknownActionCreatorWithPayload<unknown>[],
reducer: Reducer<State, unknown>
): RegisteredReducer<State, unknown>;

/**
* Define a reducer for multiple actions without payloads
*
* @see combineReducers
* @param actionCreator The action creator to assign this reducer to and
* extract payload type from
* @param reducer The reducer function
* @template `State` - The state the reducer reduces to
* @returns A registered reducer that can be passed into `combineReducers`, or
* called directly as if it was the `reducer` parameter itself.
*/
<State>(
actionCreator: UnknownActionCreator[],
reducer: Reducer<State, VoidPayload>
): RegisteredReducer<State, VoidPayload>;

/**
* Define a reducer for an action with payload
*
* @see combineReducers
* @param actionCreator The action creator to assign this reducer to and
* extract payload type from
* @param reducer The reducer function
* @template `State` - The state the reducer reduces to
* @template `Payload` - The payload of the action, fed to the reducer together
* with the state. Should be automatically extracted from
* the `actionCreator` parameter
* @returns A registered reducer that can be passed into `combineReducers`, or
* called directly as if it was the `reducer` parameter itself.
*/
<State, Payload>(
actionCreator: UnknownActionCreatorWithPayload<Payload>,
reducer: Reducer<State, Payload>
): RegisteredReducer<State, Payload>;

/**
* Define a reducer for an action without payload
*
* @see combineReducers
* @param actionCreator The action creator to assign this reducer to and
* extract payload type from
* @param reducer The reducer function
* @template `State` - The state the reducer reduces to
* @returns A registered reducer that can be passed into `combineReducers`, or
* called directly as if it was the `reducer` parameter itself.
*/
<State, Payload = VoidPayload>(
actionCreator: UnknownActionCreator | UnknownActionCreator[],
reducer: Reducer<State, Payload>
): RegisteredReducer<State, Payload>;
};

/**
* streamReducer
* A stream reducer is a stream operator which updates the state of a given stream with the last
* emitted state of another stream, it basically reduces the state of a given stream over another
* emitted state of another stream, meaning it reduces the state of a given stream over another
* stream.
*
* Another way of looking at it is in terms of an action reducer this avoids creating a new action
* and dispatching it manually on every emit from the source observable. This treats the observable
* state as the action.
*
* ```ts
* // Listen for changes on context$
* streamReducer(
* context$,
* (state, context) => {
* // context changed!
* })
*
* // Listen for specific changes on context$
* streamReducer(
* context$.pipe(
* map(context => ({ id })),
* distinctUntilChanged()
* ),
* (state, contextId) => {
* // contextId changed!
* })
* ```
*
* @param source The observable that the reducer function should be subscribed to, which act as
* the "action" of the reducer.
* @param reducerFn The reducer function with signature:
* (prevState, observableInput) => nextState
* @returns A wrapped reducer function for use with persistedReducedStream, combineReducers etc.
*/
export const streamReducer: StreamReducerCreator = <State, EmittedState>(
export const streamReducer = <State, EmittedState>(
source: ObservableInput<EmittedState>,
reducerFn: Reducer<State, EmittedState>
) => {
): RegisteredReducer<State, EmittedState> => {
const wrappedStreamReducer = (
state: State,
emittedState: EmittedState,
Expand All @@ -198,49 +105,57 @@ export const streamReducer: StreamReducerCreator = <State, EmittedState>(

/**
* actionReducer
* A action reducer is a stream operator which allows to update the state of a given stream based
* on a given action with the payload of that action.
* A action reducer is a stream operator which triggers its reducer when a
* relevant action is dispatched to the action$
*
* @param actionCreator One or multiple actions that should run the reducer
* @param actionCreator The actionCreator that creates the action that should run the reducer
* @param reducerFn The reducer function with signature: (prevState, action) => newState
* @returns A wrapped reducer function for use with persistedReducedStream, combineReducers etc.
*/
export const actionReducer: ActionReducerCreator = <State, ActionPayload = any>(
actionCreator: UnknownActionCreator | UnknownActionCreator[],
reducerFn: Reducer<State, ActionPayload>
) => {
export const actionReducer = <State, Payload>(
actionCreator: ActionCreator<Payload>,
reducerFn: Reducer<State, Payload>
): RegisteredReducer<State, Payload> => {
const wrappedActionReducer = (
state: State,
payload: ActionPayload,
payload: Payload,
namespace?: string
) => reducerFn(state, payload, namespace);

wrappedActionReducer.trigger = {
actions: wrapInArray(actionCreator),
actions: [actionCreator],
};

return wrappedActionReducer;
};

/**
* @deprecated since version 2.4.0
* Use actionReducer or streamReducer instead
* @deprecated
* v2.6.0, use actionReducer or streamReducer instead.
* If using multi-action reducers you have to split them into individual reducers
*/
export const reducer: StreamReducerCreator & ActionReducerCreator = <
State,
Payload = any
>(
export const reducer = <State, Payload>(
trigger:
| UnknownActionCreator
| UnknownActionCreator[]
| ActionCreator<Payload>
| ActionCreator<Payload>[]
| ObservableInput<Payload>,
reducerFn: Reducer<State, Payload>
) => {
): RegisteredReducer<State, Payload> => {
if (!Array.isArray(trigger) && isObservableInput(trigger)) {
return streamReducer(trigger, reducerFn);
} else {
return actionReducer(trigger, reducerFn);
}

const wrappedActionReducer = (
state: State,
payload: Payload,
namespace?: string
) => reducerFn(state, payload, namespace);

wrappedActionReducer.trigger = {
actions: wrapInArray(trigger),
};

return wrappedActionReducer;
};

const ACTION_ORIGIN = Symbol('Action origin');
Expand Down

0 comments on commit 9531ca0

Please sign in to comment.