Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
add isAction helper function, and ensure listener middleware only run…
…s for actions
  • Loading branch information
ben.durrant committed Apr 17, 2023
commit 482270e6aa6db7a2b1449bcf26b40f2a9979eac3
18 changes: 14 additions & 4 deletions packages/toolkit/src/createAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ export type PayloadActionCreator<
* A utility function to create an action creator for the given action type
* string. The action creator accepts a single argument, which will be included
* in the action object as a field called payload. The action creator function
* will also have its toString() overriden so that it returns the action type,
* will also have its toString() overridden so that it returns the action type,
* allowing it to be used in reducer logic that is looking for that action type.
*
* @param type The action type to use for created actions.
Expand All @@ -241,7 +241,7 @@ export function createAction<P = void, T extends string = string>(
* A utility function to create an action creator for the given action type
* string. The action creator accepts a single argument, which will be included
* in the action object as a field called payload. The action creator function
* will also have its toString() overriden so that it returns the action type,
* will also have its toString() overridden so that it returns the action type,
* allowing it to be used in reducer logic that is looking for that action type.
*
* @param type The action type to use for created actions.
Expand Down Expand Up @@ -286,15 +286,25 @@ export function createAction(type: string, prepareAction?: Function): any {
return actionCreator
}

/**
* Returns true if value is a plain object with a `type` property.
*/
export function isAction(action: unknown): action is Action<unknown> {
return isPlainObject(action) && 'type' in action
}

/**
* Returns true if value is an action with a string type and valid Flux Standard Action keys.
*/
export function isFSA(action: unknown): action is {
type: string
payload?: unknown
error?: unknown
meta?: unknown
} {
return (
isPlainObject(action) &&
typeof (action as any).type === 'string' &&
isAction(action) &&
typeof action.type === 'string' &&
Object.keys(action).every(isValidKey)
)
}
Expand Down
2 changes: 2 additions & 0 deletions packages/toolkit/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ export {
// js
createAction,
getType,
isAction,
isFSA as isFluxStandardAction,
} from './createAction'
export type {
// types
Expand Down
7 changes: 6 additions & 1 deletion packages/toolkit/src/listenerMiddleware/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Dispatch, AnyAction, MiddlewareAPI } from 'redux'
import type { ThunkDispatch } from 'redux-thunk'
import { createAction } from '../createAction'
import { createAction, isAction } from '../createAction'
import { nanoid } from '../nanoid'

import type {
Expand Down Expand Up @@ -426,6 +426,11 @@ export function createListenerMiddleware<

const middleware: ListenerMiddleware<S, D, ExtraArgument> =
(api) => (next) => (action) => {
if (!isAction(action)) {
// we only want to notify listeners for action objects
return next(action)
}

if (addListener.match(action)) {
return startListening(action.payload)
}
Expand Down
2 changes: 1 addition & 1 deletion packages/toolkit/src/listenerMiddleware/tests/fork.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ describe('fork', () => {
},
})

store.dispatch(increment)
store.dispatch(increment())

expect(await deferredResult).toBe(listenerCompleted)
})
Expand Down