Skip to content

Commit ab58782

Browse files
authored
Merge pull request #3425 from EskiMojo14/action-to-string-remove
2 parents 0dd2d36 + 9d5adf1 commit ab58782

File tree

6 files changed

+36
-68
lines changed

6 files changed

+36
-68
lines changed

docs/api/createAction.mdx

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ const action = increment(3)
3131
// { type: 'counter/increment', payload: 3 }
3232
```
3333
34-
The `createAction` helper combines these two declarations into one. It takes an action type and returns an action creator for that type. The action creator can be called either without arguments or with a `payload` to be attached to the action. Also, the action creator overrides [toString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString) so that the action type becomes its string representation.
34+
The `createAction` helper combines these two declarations into one. It takes an action type and returns an action creator for that type. The action creator can be called either without arguments or with a `payload` to be attached to the action.
3535
3636
```ts
3737
import { createAction } from '@reduxjs/toolkit'
@@ -44,10 +44,7 @@ let action = increment()
4444
action = increment(3)
4545
// returns { type: 'counter/increment', payload: 3 }
4646

47-
console.log(increment.toString())
48-
// 'counter/increment'
49-
50-
console.log(`The action type is: ${increment}`)
47+
console.log(`The action type is: ${increment.type}`)
5148
// 'The action type is: counter/increment'
5249
```
5350
@@ -89,7 +86,7 @@ If provided, all arguments from the action creator will be passed to the prepare
8986
9087
## Usage with createReducer()
9188
92-
Because of their `toString()` override, action creators returned by `createAction()` can be used directly as keys for the case reducers passed to [createReducer()](createReducer.mdx).
89+
Action creators can be passed directly to `addCase` in a [createReducer()](createReducer.mdx) build callback.
9390
9491
```ts
9592
import { createAction, createReducer } from '@reduxjs/toolkit'
@@ -103,21 +100,23 @@ const counterReducer = createReducer(0, (builder) => {
103100
})
104101
```
105102
103+
<!-- TODO: how do we handle this? -->
104+
106105
## Non-String Action Types
107106
108107
In principle, Redux lets you use any kind of value as an action type. Instead of strings, you could theoretically use numbers, [symbols](https://developer.mozilla.org/en-US/docs/Glossary/Symbol), or anything else ([although it's recommended that the value should at least be serializable](https://redux.js.org/faq/actions#why-should-type-be-a-string-or-at-least-serializable-why-should-my-action-types-be-constants)).
109108
110-
However, Redux Toolkit rests on the assumption that you use string action types. Specifically, some of its features rely on the fact that with strings, the `toString()` method of an `createAction()` action creator returns the matching action type. This is not the case for non-string action types because `toString()` will return the string-converted type value rather than the type itself.
109+
However, Redux Toolkit rests on the assumption that you use string action types.
111110
112111
```js
113112
const INCREMENT = Symbol('increment')
114113
const increment = createAction(INCREMENT)
115114

116-
increment.toString()
115+
increment.type.toString()
117116
// returns the string 'Symbol(increment)',
118117
// not the INCREMENT symbol itself
119118

120-
increment.toString() === INCREMENT
119+
increment.type.toString() === INCREMENT
121120
// false
122121
```
123122

docs/introduction/getting-started.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ Redux Toolkit includes these APIs:
9494

9595
- [`configureStore()`](../api/configureStore.mdx): wraps `createStore` to provide simplified configuration options and good defaults. It can automatically combine your slice reducers, adds whatever Redux middleware you supply, includes `redux-thunk` by default, and enables use of the Redux DevTools Extension.
9696
- [`createReducer()`](../api/createReducer.mdx): that lets you supply a lookup table of action types to case reducer functions, rather than writing switch statements. In addition, it automatically uses the [`immer` library](https://github.com/immerjs/immer) to let you write simpler immutable updates with normal mutative code, like `state.todos[3].completed = true`.
97-
- [`createAction()`](../api/createAction.mdx): generates an action creator function for the given action type string. The function itself has `toString()` defined, so that it can be used in place of the type constant.
97+
- [`createAction()`](../api/createAction.mdx): generates an action creator function for the given action type string.
9898
- [`createSlice()`](../api/createSlice.mdx): accepts an object of reducer functions, a slice name, and an initial state value, and automatically generates a slice reducer with corresponding action creators and action types.
9999
- [`createAsyncThunk`](../api/createAsyncThunk.mdx): accepts an action type string and a function that returns a promise, and generates a thunk that dispatches `pending/fulfilled/rejected` action types based on that promise
100100
- [`createEntityAdapter`](../api/createEntityAdapter.mdx): generates a set of reusable reducers and selectors to manage normalized data in the store

docs/usage/usage-guide.md

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -280,24 +280,16 @@ addTodo({ text: 'Buy milk' })
280280

281281
### Using Action Creators as Action Types
282282

283-
Redux reducers need to look for specific action types to determine how they should update their state. Normally, this is done by defining action type strings and action creator functions separately. Redux Toolkit `createAction` function uses a couple tricks to make this easier.
284-
285-
First, `createAction` overrides the `toString()` method on the action creators it generates. **This means that the action creator itself can be used as the "action type" reference in some places**, such as the keys provided to `builder.addCase` or the `createReducer` object notation.
286-
287-
Second, the action type is also defined as a `type` field on the action creator.
283+
Redux reducers need to look for specific action types to determine how they should update their state. Normally, this is done by defining action type strings and action creator functions separately. Redux Toolkit `createAction` function make this easier, by defining the action type as a `type` field on the action creator.
288284

289285
```js
290286
const actionCreator = createAction('SOME_ACTION_TYPE')
291287

292-
console.log(actionCreator.toString())
293-
// "SOME_ACTION_TYPE"
294-
295288
console.log(actionCreator.type)
296289
// "SOME_ACTION_TYPE"
297290

298291
const reducer = createReducer({}, (builder) => {
299-
// actionCreator.toString() will automatically be called here
300-
// also, if you use TypeScript, the action type will be correctly inferred
292+
// if you use TypeScript, the action type will be correctly inferred
301293
builder.addCase(actionCreator, (state, action) => {})
302294

303295
// Or, you can reference the .type field:
@@ -308,7 +300,7 @@ const reducer = createReducer({}, (builder) => {
308300

309301
This means you don't have to write or use a separate action type variable, or repeat the name and value of an action type like `const SOME_ACTION_TYPE = "SOME_ACTION_TYPE"`.
310302

311-
Unfortunately, the implicit conversion to a string doesn't happen for switch statements. If you want to use one of these action creators in a switch statement, you need to call `actionCreator.toString()` yourself:
303+
If you want to use one of these action creators in a switch statement, you need to call `actionCreator.type` yourself:
312304

313305
```js
314306
const actionCreator = createAction('SOME_ACTION_TYPE')
@@ -320,19 +312,13 @@ const reducer = (state = {}, action) => {
320312
break
321313
}
322314
// CORRECT: this will work as expected
323-
case actionCreator.toString(): {
324-
break
325-
}
326-
// CORRECT: this will also work right
327315
case actionCreator.type: {
328316
break
329317
}
330318
}
331319
}
332320
```
333321

334-
If you are using Redux Toolkit with TypeScript, note that the TypeScript compiler may not accept the implicit `toString()` conversion when the action creator is used as an object key. In that case, you may need to either manually cast it to a string (`actionCreator as string`), or use the `.type` field as the key.
335-
336322
## Creating Slices of State
337323

338324
Redux state is typically organized into "slices", defined by the reducers that are passed to `combineReducers`:

packages/toolkit/src/createAction.ts

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -224,9 +224,7 @@ export type PayloadActionCreator<
224224
/**
225225
* A utility function to create an action creator for the given action type
226226
* string. The action creator accepts a single argument, which will be included
227-
* in the action object as a field called payload. The action creator function
228-
* will also have its toString() overridden so that it returns the action type,
229-
* allowing it to be used in reducer logic that is looking for that action type.
227+
* in the action object as a field called payload.
230228
*
231229
* @param type The action type to use for created actions.
232230
* @param prepare (optional) a method that takes any number of arguments and returns { payload } or { payload, meta }.
@@ -241,9 +239,7 @@ export function createAction<P = void, T extends string = string>(
241239
/**
242240
* A utility function to create an action creator for the given action type
243241
* string. The action creator accepts a single argument, which will be included
244-
* in the action object as a field called payload. The action creator function
245-
* will also have its toString() overridden so that it returns the action type,
246-
* allowing it to be used in reducer logic that is looking for that action type.
242+
* in the action object as a field called payload.
247243
*
248244
* @param type The action type to use for created actions.
249245
* @param prepare (optional) a method that takes any number of arguments and returns { payload } or { payload, meta }.
@@ -277,8 +273,6 @@ export function createAction(type: string, prepareAction?: Function): any {
277273
return { type, payload: args[0] }
278274
}
279275

280-
actionCreator.toString = () => `${type}`
281-
282276
actionCreator.type = type
283277

284278
actionCreator.match = (action: Action<string>): action is PayloadAction =>
@@ -328,22 +322,6 @@ function isValidKey(key: string) {
328322
return ['type', 'payload', 'error', 'meta'].indexOf(key) > -1
329323
}
330324

331-
/**
332-
* Returns the action type of the actions created by the passed
333-
* `createAction()`-generated action creator (arbitrary action creators
334-
* are not supported).
335-
*
336-
* @param action The action creator whose action type to get.
337-
* @returns The action type used by the action creator.
338-
*
339-
* @public
340-
*/
341-
export function getType<T extends string>(
342-
actionCreator: PayloadActionCreator<any, T>
343-
): T {
344-
return `${actionCreator}` as T
345-
}
346-
347325
// helper types for more readable typings
348326

349327
type IfPrepareActionMethodProvided<

packages/toolkit/src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ export type { DevToolsEnhancerOptions } from './devtoolsExtension'
3030
export {
3131
// js
3232
createAction,
33-
getType,
3433
isAction,
3534
isActionCreator,
3635
isFSA as isFluxStandardAction,

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

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createAction, getType, isAction } from '@reduxjs/toolkit'
1+
import { createAction, isAction, isActionCreator } from '@reduxjs/toolkit'
22

33
describe('createAction', () => {
44
it('should create an action', () => {
@@ -9,13 +9,6 @@ describe('createAction', () => {
99
})
1010
})
1111

12-
describe('when stringifying action', () => {
13-
it('should return the action type', () => {
14-
const actionCreator = createAction('A_TYPE')
15-
expect(`${actionCreator}`).toEqual('A_TYPE')
16-
})
17-
})
18-
1912
describe('when passing a prepareAction method only returning a payload', () => {
2013
it('should use the payload returned from the prepareAction method', () => {
2114
const actionCreator = createAction('A_TYPE', (a: number) => ({
@@ -122,12 +115,13 @@ describe('createAction', () => {
122115
})
123116
})
124117

118+
const actionCreator = createAction('anAction')
119+
120+
class Action {
121+
type = 'totally an action'
122+
}
125123
describe('isAction', () => {
126124
it('should only return true for plain objects with a type property', () => {
127-
const actionCreator = createAction('anAction')
128-
class Action {
129-
type = 'totally an action'
130-
}
131125
const testCases: [action: unknown, expected: boolean][] = [
132126
[{ type: 'an action' }, true],
133127
[{ type: 'more props', extra: true }, true],
@@ -143,9 +137,21 @@ describe('isAction', () => {
143137
})
144138
})
145139

146-
describe('getType', () => {
147-
it('should return the action type', () => {
148-
const actionCreator = createAction('A_TYPE')
149-
expect(getType(actionCreator)).toEqual('A_TYPE')
140+
describe('isActionCreator', () => {
141+
it('should only return true for action creators', () => {
142+
expect(isActionCreator(actionCreator)).toBe(true)
143+
const notActionCreators = [
144+
{ type: 'an action' },
145+
{ type: 'more props', extra: true },
146+
actionCreator(),
147+
Promise.resolve({ type: 'an action' }),
148+
new Action(),
149+
false,
150+
'a string',
151+
false,
152+
]
153+
for (const notActionCreator of notActionCreators) {
154+
expect(isActionCreator(notActionCreator)).toBe(false)
155+
}
150156
})
151157
})

0 commit comments

Comments
 (0)