Skip to content

Commit fd31cdc

Browse files
committed
Update createSlice to accept a lazy init function
1 parent e6a1d48 commit fd31cdc

File tree

3 files changed

+54
-3
lines changed

3 files changed

+54
-3
lines changed

packages/toolkit/src/createReducer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export type CaseReducers<S, AS extends Actions> = {
6666
[T in keyof AS]: AS[T] extends Action ? CaseReducer<S, AS[T]> : void
6767
}
6868

69-
type NotFunction<T> = T extends Function ? never : T
69+
export type NotFunction<T> = T extends Function ? never : T
7070

7171
function isStateFunction<S>(x: unknown): x is () => S {
7272
return typeof x === 'function'

packages/toolkit/src/createSlice.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import type {
88
} from './createAction'
99
import { createAction } from './createAction'
1010
import type { CaseReducer, CaseReducers } from './createReducer'
11-
import { createReducer } from './createReducer'
11+
import { createReducer, NotFunction } from './createReducer'
1212
import type { ActionReducerMapBuilder } from './mapBuilders'
1313
import { executeReducerBuilderCallback } from './mapBuilders'
1414
import type { NoInfer } from './tsHelpers'
@@ -53,6 +53,12 @@ export interface Slice<
5353
* This enables reuse and testing if they were defined inline when calling `createSlice`.
5454
*/
5555
caseReducers: SliceDefinedCaseReducers<CaseReducers>
56+
57+
/**
58+
* Provides access to the initial state value given to the slice.
59+
* If a lazy state initializer was provided, it will be called and a fresh value returned.
60+
*/
61+
getInitialState: () => State
5662
}
5763

5864
/**
@@ -72,8 +78,10 @@ export interface CreateSliceOptions<
7278

7379
/**
7480
* The initial state to be returned by the slice reducer.
81+
* This may optionally be a "lazy state initializer" that returns the
82+
* intended initial state value when called.
7583
*/
76-
initialState: State
84+
initialState: State | (() => State)
7785

7886
/**
7987
* A mapping from action types to action-type-specific *case reducer*
@@ -301,5 +309,6 @@ export function createSlice<
301309
reducer,
302310
actions: actionCreators as any,
303311
caseReducers: sliceCaseReducersByName as any,
312+
getInitialState: reducer.getInitialState,
304313
}
305314
}

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

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,48 @@ describe('createSlice', () => {
6363
expect(caseReducers.increment).toBeTruthy()
6464
expect(typeof caseReducers.increment).toBe('function')
6565
})
66+
67+
it('getInitialState should return the state', () => {
68+
const initialState = 42
69+
const slice = createSlice({
70+
name: 'counter',
71+
initialState,
72+
reducers: {},
73+
})
74+
75+
expect(slice.getInitialState()).toBe(initialState)
76+
})
77+
})
78+
79+
describe('when initialState is a function', () => {
80+
const initialState = () => ({ user: '' })
81+
82+
const { actions, reducer } = createSlice({
83+
reducers: {
84+
setUserName: (state, action) => {
85+
state.user = action.payload
86+
},
87+
},
88+
initialState,
89+
name: 'user',
90+
})
91+
92+
it('should set the username', () => {
93+
expect(reducer(undefined, actions.setUserName('eric'))).toEqual({
94+
user: 'eric',
95+
})
96+
})
97+
98+
it('getInitialState should return the state', () => {
99+
const initialState = () => 42
100+
const slice = createSlice({
101+
name: 'counter',
102+
initialState,
103+
reducers: {},
104+
})
105+
106+
expect(slice.getInitialState()).toBe(42)
107+
})
66108
})
67109

68110
describe('when mutating state object', () => {

0 commit comments

Comments
 (0)