Skip to content

Commit f2b60e9

Browse files
committed
Added note about circular type issues.
1 parent 0116fcc commit f2b60e9

File tree

1 file changed

+65
-0
lines changed

1 file changed

+65
-0
lines changed

docs/api/createSlice.mdx

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,71 @@ A set of selectors that receive the slice state as their first parameter, and an
353353

354354
Each selector will have a corresponding key in the resulting [`selectors`](#selectors-1) object.
355355

356+
:::caution Circular types
357+
358+
It's fairly common to have selectors that use other selectors. This is still possible with slice selectors, but defining a selector without a return type can cause a circular type inference problem:
359+
360+
```ts no-transpile
361+
const counterSlice = createSlice({
362+
name: 'counter',
363+
initialState: { value: 0 },
364+
reducers: {},
365+
selectors: {
366+
selectValue: (state) => state.value,
367+
// highlight-start
368+
// this creates a cycle, because it's inferring a type from the object we're creating here
369+
selectTimes: (state, times = 1) =>
370+
counterSlice.getSelectors().selectValue(state) * times,
371+
// highlight-end
372+
},
373+
})
374+
```
375+
376+
This cycle can be fixed by providing an explicit return type for the selector:
377+
378+
```ts no-transpile
379+
const counterSlice = createSlice({
380+
name: 'counter',
381+
initialState: { value: 0 },
382+
reducers: {},
383+
selectors: {
384+
selectValue: (state) => state.value,
385+
// highlight-start
386+
// explicit return type means cycle is broken
387+
selectTimes: (state, times = 1): number =>
388+
counterSlice.getSelectors().selectValue(state) * times,
389+
// highlight-end
390+
},
391+
})
392+
```
393+
394+
This limitation may be also encountered when using a slice's `asyncThunk` creator.
395+
In the same way, the issue is resolved by explicitly providing a type somewhere in the chain and breaking the cycle.
396+
397+
```ts no-transpile
398+
const counterSlice = createSlice({
399+
name: 'counter',
400+
initialState: { value: 0 },
401+
reducers: (create) => ({
402+
getCountData: create.asyncThunk(async (_arg, { getState }) => {
403+
const currentCount = counterSlice.selectors.selectValue(
404+
getState() as RootState
405+
)
406+
// highlight-start
407+
// this would cause a circular type, but the type annotation breaks the circle
408+
const result: Response = await fetch('api/' + currentCount)
409+
// highlight-end
410+
return result.json()
411+
}),
412+
}),
413+
selectors: {
414+
selectValue: (state) => state.value,
415+
},
416+
})
417+
```
418+
419+
:::
420+
356421
## Return Value
357422

358423
`createSlice` will return an object that looks like:

0 commit comments

Comments
 (0)