Skip to content

Commit d2be143

Browse files
committed
correctly enforce meta and error types as returned from prepare
1 parent ec0d752 commit d2be143

File tree

2 files changed

+65
-4
lines changed

2 files changed

+65
-4
lines changed

src/createSlice.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ export type CaseReducerWithPrepare<State, Action extends PayloadAction> = {
110110
export type SliceCaseReducers<State> = {
111111
[K: string]:
112112
| CaseReducer<State, PayloadAction<any>>
113-
| CaseReducerWithPrepare<State, PayloadAction<any>>
113+
| CaseReducerWithPrepare<State, PayloadAction<any, string, any, any>>
114114
}
115115

116116
/**
@@ -187,11 +187,13 @@ export type ValidateSliceCaseReducers<
187187
ACR extends SliceCaseReducers<S>
188188
> = ACR &
189189
{
190-
[P in keyof ACR]: ACR[P] extends {
191-
reducer(s: S, action?: { payload: infer O }): any
190+
[T in keyof ACR]: ACR[T] extends {
191+
prepare(
192+
...a: never[]
193+
): { payload: infer P; meta?: infer M; error?: infer E }
192194
}
193195
? {
194-
prepare(...a: never[]): { payload: O }
196+
reducer(s: S, action: PayloadAction<P, string, M, E>): any
195197
}
196198
: {}
197199
}

type-tests/files/createSlice.typetest.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,65 @@ function expectType<T>(t: T) {
175175
expectType<string>(counter.actions.concatMetaStrLen('test').meta)
176176
}
177177

178+
/**
179+
* Test: access meta and error from reducer
180+
*/
181+
{
182+
const counter = createSlice({
183+
name: 'test',
184+
initialState: { counter: 0, concat: '' },
185+
reducers: {
186+
// case: meta and error not used in reducer
187+
testDefaultMetaAndError: {
188+
reducer(_, action: PayloadAction<number, string>) {},
189+
prepare: (payload: number) => ({
190+
payload,
191+
meta: 'meta' as 'meta',
192+
error: 'error' as 'error'
193+
})
194+
},
195+
// case: meta and error marked as "unknown" in reducer
196+
testUnknownMetaAndError: {
197+
reducer(_, action: PayloadAction<number, string, unknown, unknown>) {},
198+
prepare: (payload: number) => ({
199+
payload,
200+
meta: 'meta' as 'meta',
201+
error: 'error' as 'error'
202+
})
203+
},
204+
// case: meta and error are typed in the reducer as returned by prepare
205+
testMetaAndError: {
206+
reducer(_, action: PayloadAction<number, string, 'meta', 'error'>) {},
207+
prepare: (payload: number) => ({
208+
payload,
209+
meta: 'meta' as 'meta',
210+
error: 'error' as 'error'
211+
})
212+
},
213+
// case: meta is typed differently in the reducer than returned from prepare
214+
testErroneousMeta: {
215+
// typings:expect-error
216+
reducer(_, action: PayloadAction<number, string, 'meta', 'error'>) {},
217+
prepare: (payload: number) => ({
218+
payload,
219+
meta: 1,
220+
error: 'error' as 'error'
221+
})
222+
},
223+
// case: error is typed differently in the reducer than returned from prepare
224+
testErroneousError: {
225+
// typings:expect-error
226+
reducer(_, action: PayloadAction<number, string, 'meta', 'error'>) {},
227+
prepare: (payload: number) => ({
228+
payload,
229+
meta: 'meta' as 'meta',
230+
error: 1
231+
})
232+
}
233+
}
234+
})
235+
}
236+
178237
/*
179238
* Test: returned case reducer has the correct type
180239
*/

0 commit comments

Comments
 (0)