Skip to content

Commit 8af52c1

Browse files
committed
ensure all actions have a string type
1 parent e9dfc93 commit 8af52c1

File tree

4 files changed

+20
-19
lines changed

4 files changed

+20
-19
lines changed

packages/toolkit/src/createAction.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export type _ActionCreatorWithPreparedPayload<
8484
*/
8585
export interface BaseActionCreator<P, T extends string, M = never, E = never> {
8686
type: T
87-
match: (action: Action<unknown>) => action is PayloadAction<P, T, M, E>
87+
match: (action: Action<string>) => action is PayloadAction<P, T, M, E>
8888
}
8989

9090
/**
@@ -290,8 +290,12 @@ export function createAction(type: string, prepareAction?: Function): any {
290290
/**
291291
* Returns true if value is a plain object with a `type` property.
292292
*/
293-
export function isAction(action: unknown): action is Action<unknown> {
294-
return isPlainObject(action) && 'type' in action
293+
export function isAction(action: unknown): action is Action<string> {
294+
return (
295+
isPlainObject(action) &&
296+
'type' in action &&
297+
typeof (action as Record<'type', unknown>).type === 'string'
298+
)
295299
}
296300

297301
/**
@@ -317,11 +321,7 @@ export function isFSA(action: unknown): action is {
317321
error?: unknown
318322
meta?: unknown
319323
} {
320-
return (
321-
isAction(action) &&
322-
typeof action.type === 'string' &&
323-
Object.keys(action).every(isValidKey)
324-
)
324+
return isAction(action) && Object.keys(action).every(isValidKey)
325325
}
326326

327327
function isValidKey(key: string) {

packages/toolkit/src/tests/createAction.typetest.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ import { expectType } from './helpers'
258258
// simple use case
259259
{
260260
const actionCreator = createAction<string, 'test'>('test')
261-
const x: Action<unknown> = {} as any
261+
const x: Action<string> = {} as any
262262
if (actionCreator.match(x)) {
263263
expectType<'test'>(x.type)
264264
expectType<string>(x.payload)
@@ -273,7 +273,7 @@ import { expectType } from './helpers'
273273
// special case: optional argument
274274
{
275275
const actionCreator = createAction<string | undefined, 'test'>('test')
276-
const x: Action<unknown> = {} as any
276+
const x: Action<string> = {} as any
277277
if (actionCreator.match(x)) {
278278
expectType<'test'>(x.type)
279279
expectType<string | undefined>(x.payload)
@@ -283,7 +283,7 @@ import { expectType } from './helpers'
283283
// special case: without argument
284284
{
285285
const actionCreator = createAction('test')
286-
const x: Action<unknown> = {} as any
286+
const x: Action<string> = {} as any
287287
if (actionCreator.match(x)) {
288288
expectType<'test'>(x.type)
289289
// @ts-expect-error
@@ -298,7 +298,7 @@ import { expectType } from './helpers'
298298
meta: '',
299299
error: false,
300300
}))
301-
const x: Action<unknown> = {} as any
301+
const x: Action<string> = {} as any
302302
if (actionCreator.match(x)) {
303303
expectType<'test'>(x.type)
304304
expectType<string>(x.payload)
@@ -315,7 +315,7 @@ import { expectType } from './helpers'
315315
// potential use: as array filter
316316
{
317317
const actionCreator = createAction<string, 'test'>('test')
318-
const x: Array<Action<unknown>> = []
318+
const x: Array<Action<string>> = []
319319
expectType<Array<PayloadAction<string, 'test'>>>(
320320
x.filter(actionCreator.match)
321321
)

packages/toolkit/src/tests/createSlice.typetest.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -386,13 +386,13 @@ const value = actionCreators.anyKey
386386
},
387387
})
388388

389-
const x: Action<unknown> = {} as any
389+
const x: Action<string> = {} as any
390390
if (mySlice.actions.setName.match(x)) {
391391
expectType<'name/setName'>(x.type)
392392
expectType<string>(x.payload)
393393
} else {
394394
// @ts-expect-error
395-
expectType<string>(x.type)
395+
expectType<'name/setName'>(x.type)
396396
// @ts-expect-error
397397
expectType<string>(x.payload)
398398
}

packages/toolkit/src/tests/serializableStateInvariantMiddleware.test.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,15 +103,16 @@ describe('serializableStateInvariantMiddleware', () => {
103103
middleware: [serializableStateInvariantMiddleware],
104104
})
105105

106-
const type = Symbol.for('SOME_CONSTANT')
107-
const dispatchedAction = { type }
106+
const symbol = Symbol.for('SOME_CONSTANT')
107+
const dispatchedAction = { type: 'an-action', payload: symbol }
108108

109109
store.dispatch(dispatchedAction)
110110

111111
expect(getLog().log).toMatchInlineSnapshot(`
112-
"A non-serializable value was detected in an action, in the path: \`type\`. Value: Symbol(SOME_CONSTANT)
112+
"A non-serializable value was detected in an action, in the path: \`payload\`. Value: Symbol(SOME_CONSTANT)
113113
Take a look at the logic that dispatched this action: Object {
114-
\\"type\\": Symbol(SOME_CONSTANT),
114+
\\"payload\\": Symbol(SOME_CONSTANT),
115+
\\"type\\": \\"an-action\\",
115116
}
116117
(See https://redux.js.org/faq/actions#why-should-type-be-a-string-or-at-least-serializable-why-should-my-action-types-be-constants)
117118
(To allow non-serializable values see: https://redux-toolkit.js.org/usage/usage-guide#working-with-non-serializable-data)"

0 commit comments

Comments
 (0)