Skip to content

Commit 762f161

Browse files
authored
strongly type slice name (#354)
* strongly type slice name * move new generic to the end and default it to string
1 parent 9842933 commit 762f161

File tree

3 files changed

+57
-21
lines changed

3 files changed

+57
-21
lines changed

etc/redux-toolkit.api.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,13 @@ export { createSelector }
112112
export function createSerializableStateInvariantMiddleware(options?: SerializableStateInvariantMiddlewareOptions): Middleware;
113113

114114
// @public
115-
export function createSlice<State, CaseReducers extends SliceCaseReducers<State>>(options: CreateSliceOptions<State, CaseReducers>): Slice<State, CaseReducers>;
115+
export function createSlice<State, CaseReducers extends SliceCaseReducers<State>, Name extends string = string>(options: CreateSliceOptions<State, CaseReducers, Name>): Slice<State, CaseReducers, Name>;
116116

117117
// @public
118-
export interface CreateSliceOptions<State = any, CR extends SliceCaseReducers<State> = SliceCaseReducers<State>> {
118+
export interface CreateSliceOptions<State = any, CR extends SliceCaseReducers<State> = SliceCaseReducers<State>, Name extends string = string> {
119119
extraReducers?: CaseReducers<NoInfer<State>, any> | ((builder: ActionReducerMapBuilder<NoInfer<State>>) => void);
120120
initialState: State;
121-
name: string;
121+
name: Name;
122122
reducers: ValidateSliceCaseReducers<State, CR>;
123123
}
124124

@@ -182,10 +182,10 @@ export interface SerializableStateInvariantMiddlewareOptions {
182182
}
183183

184184
// @public
185-
export interface Slice<State = any, CaseReducers extends SliceCaseReducers<State> = SliceCaseReducers<State>> {
185+
export interface Slice<State = any, CaseReducers extends SliceCaseReducers<State> = SliceCaseReducers<State>, Name extends string = string> {
186186
actions: CaseReducerActions<CaseReducers>;
187187
caseReducers: SliceDefinedCaseReducers<CaseReducers>;
188-
name: string;
188+
name: Name;
189189
reducer: Reducer<State>;
190190
}
191191

src/createSlice.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { Reducer } from 'redux'
22
import {
3+
ActionCreatorWithoutPayload,
34
createAction,
45
PayloadAction,
56
PayloadActionCreator,
67
PrepareAction,
7-
ActionCreatorWithoutPayload,
88
_ActionCreatorWithPreparedPayload
99
} from './createAction'
10-
import { createReducer, CaseReducers, CaseReducer } from './createReducer'
10+
import { CaseReducer, CaseReducers, createReducer } from './createReducer'
1111
import {
1212
ActionReducerMapBuilder,
1313
executeReducerBuilderCallback
@@ -30,12 +30,13 @@ export type SliceActionCreator<P> = PayloadActionCreator<P>
3030
*/
3131
export interface Slice<
3232
State = any,
33-
CaseReducers extends SliceCaseReducers<State> = SliceCaseReducers<State>
33+
CaseReducers extends SliceCaseReducers<State> = SliceCaseReducers<State>,
34+
Name extends string = string
3435
> {
3536
/**
3637
* The slice name.
3738
*/
38-
name: string
39+
name: Name
3940

4041
/**
4142
* The slice's reducer.
@@ -62,12 +63,13 @@ export interface Slice<
6263
*/
6364
export interface CreateSliceOptions<
6465
State = any,
65-
CR extends SliceCaseReducers<State> = SliceCaseReducers<State>
66+
CR extends SliceCaseReducers<State> = SliceCaseReducers<State>,
67+
Name extends string = string
6668
> {
6769
/**
6870
* The slice's name. Used to namespace the generated action types.
6971
*/
70-
name: string
72+
name: Name
7173

7274
/**
7375
* The initial state to be returned by the slice reducer.
@@ -213,10 +215,11 @@ function getType(slice: string, actionKey: string): string {
213215
*/
214216
export function createSlice<
215217
State,
216-
CaseReducers extends SliceCaseReducers<State>
218+
CaseReducers extends SliceCaseReducers<State>,
219+
Name extends string = string
217220
>(
218-
options: CreateSliceOptions<State, CaseReducers>
219-
): Slice<State, CaseReducers> {
221+
options: CreateSliceOptions<State, CaseReducers, Name>
222+
): Slice<State, CaseReducers, Name> {
220223
const { name, initialState } = options
221224
if (!name) {
222225
throw new Error('`name` is a required option for createSlice')

type-tests/files/createSlice.typetest.ts

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,55 @@
1-
import { AnyAction, Reducer, Action } from 'redux'
1+
import { Action, AnyAction, Reducer } from 'redux'
2+
import { ValidateSliceCaseReducers } from 'src/createSlice'
23
import {
3-
createSlice,
4-
PayloadAction,
5-
createAction,
6-
ActionReducerMapBuilder,
7-
ActionCreatorWithOptionalPayload,
84
ActionCreatorWithNonInferrablePayload,
5+
ActionCreatorWithOptionalPayload,
96
ActionCreatorWithoutPayload,
107
ActionCreatorWithPayload,
118
ActionCreatorWithPreparedPayload,
9+
ActionReducerMapBuilder,
10+
createAction,
11+
createSlice,
12+
PayloadAction,
1213
SliceCaseReducers
1314
} from '../../src'
14-
import { ValidateSliceCaseReducers } from 'src/createSlice'
1515

1616
function expectType<T>(t: T) {
1717
return t
1818
}
1919

20+
/*
21+
* Test: Slice name is strongly typed.
22+
*/
23+
24+
const counterSlice = createSlice({
25+
name: 'counter',
26+
initialState: 0,
27+
reducers: {
28+
increment: (state: number, action) => state + action.payload,
29+
decrement: (state: number, action) => state - action.payload
30+
}
31+
})
32+
33+
const uiSlice = createSlice({
34+
name: 'ui',
35+
initialState: 0,
36+
reducers: {
37+
goToNext: (state: number, action) => state + action.payload,
38+
goToPrevious: (state: number, action) => state - action.payload
39+
}
40+
})
41+
42+
const actionCreators = {
43+
[counterSlice.name]: { ...counterSlice.actions },
44+
[uiSlice.name]: { ...uiSlice.actions }
45+
}
46+
47+
expectType<typeof counterSlice.actions>(actionCreators.counter)
48+
expectType<typeof uiSlice.actions>(actionCreators.ui)
49+
50+
// typings:expect-error
51+
const value = actionCreators.anyKey
52+
2053
/*
2154
* Test: createSlice() infers the returned slice's type.
2255
*/

0 commit comments

Comments
 (0)