From b9297e6e0505b90551d2a04cbe86c9d41595a623 Mon Sep 17 00:00:00 2001 From: Lenz Weber Date: Sun, 17 Apr 2022 20:54:58 +0200 Subject: [PATCH] createSlice: use template literal types for action type --- packages/toolkit/src/createSlice.ts | 36 +++++++++++++------ .../toolkit/src/tests/createSlice.typetest.ts | 17 +++++---- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/packages/toolkit/src/createSlice.ts b/packages/toolkit/src/createSlice.ts index 341929b15a..60376e1e3f 100644 --- a/packages/toolkit/src/createSlice.ts +++ b/packages/toolkit/src/createSlice.ts @@ -52,7 +52,7 @@ export interface Slice< * Action creators for the types of actions that are handled by the slice * reducer. */ - actions: CaseReducerActions + actions: CaseReducerActions /** * The individual case reducer functions that were passed in the `reducers` parameter. @@ -165,15 +165,29 @@ export type SliceCaseReducers = { | CaseReducerWithPrepare> } +type SliceActionType< + SliceName extends string, + ActionName extends keyof any +> = ActionName extends string | number ? `${SliceName}/${ActionName}` : string + /** * Derives the slice's `actions` property from the `reducers` options * * @public */ -export type CaseReducerActions> = { +export type CaseReducerActions< + CaseReducers extends SliceCaseReducers, + SliceName extends string +> = { [Type in keyof CaseReducers]: CaseReducers[Type] extends { prepare: any } - ? ActionCreatorForCaseReducerWithPrepare - : ActionCreatorForCaseReducer + ? ActionCreatorForCaseReducerWithPrepare< + CaseReducers[Type], + SliceActionType + > + : ActionCreatorForCaseReducer< + CaseReducers[Type], + SliceActionType + > } /** @@ -181,22 +195,24 @@ export type CaseReducerActions> = { * * @internal */ -type ActionCreatorForCaseReducerWithPrepare = - _ActionCreatorWithPreparedPayload +type ActionCreatorForCaseReducerWithPrepare< + CR extends { prepare: any }, + Type extends string +> = _ActionCreatorWithPreparedPayload /** * Get a `PayloadActionCreator` type for a passed `CaseReducer` * * @internal */ -type ActionCreatorForCaseReducer = CR extends ( +type ActionCreatorForCaseReducer = CR extends ( state: any, action: infer Action ) => any ? Action extends { payload: infer P } - ? PayloadActionCreator

- : ActionCreatorWithoutPayload - : ActionCreatorWithoutPayload + ? PayloadActionCreator + : ActionCreatorWithoutPayload + : ActionCreatorWithoutPayload /** * Extracts the CaseReducers out of a `reducers` object, even if they are diff --git a/packages/toolkit/src/tests/createSlice.typetest.ts b/packages/toolkit/src/tests/createSlice.typetest.ts index 439a9298db..287187c32a 100644 --- a/packages/toolkit/src/tests/createSlice.typetest.ts +++ b/packages/toolkit/src/tests/createSlice.typetest.ts @@ -154,12 +154,13 @@ const value = actionCreators.anyKey }, }) - const s: string = counter.actions.increment.type - const t: string = counter.actions.decrement.type - const u: string = counter.actions.multiply.type + const s: 'counter/increment' = counter.actions.increment.type + const sa: 'counter/increment' = counter.actions.increment().type + const t: 'counter/decrement' = counter.actions.decrement.type + const ta: 'counter/decrement' = counter.actions.decrement().type + const u: 'counter/multiply' = counter.actions.multiply.type + const ua: 'counter/multiply' = counter.actions.multiply(1).type - // @ts-expect-error - const x: 'counter/increment' = counter.actions.increment.type // @ts-expect-error const y: 'increment' = counter.actions.increment.type } @@ -192,7 +193,9 @@ const value = actionCreators.anyKey }, }) - expectType(counter.actions.incrementByStrLen('test').type) + expectType<'test/incrementByStrLen'>( + counter.actions.incrementByStrLen('test').type + ) expectType(counter.actions.incrementByStrLen('test').payload) expectType(counter.actions.concatMetaStrLen('test').payload) expectType(counter.actions.concatMetaStrLen('test').meta) @@ -384,7 +387,7 @@ const value = actionCreators.anyKey const x: Action = {} as any if (mySlice.actions.setName.match(x)) { - expectType(x.type) + expectType<'name/setName'>(x.type) expectType(x.payload) } else { // @ts-expect-error