Repository: reduxjs/redux-toolkit
Pull request #290 (2019-12-21 19:12:07)

exportable case reducers type, bugfix, documentation
This is what I'm currently working on and it has already gotten a bit bigger than expected :smile: 

INCLUDED:
- [x] change signatue of `createSlice` and add new types (exported) to be used in situations like #276 and #286 :
  - `SliceCaseReducerDefinitions`
  - `CaseReducerActions`
  - `CaseReducerWithPrepare` (not really necessary to export this, but `CaseReducer` was already exported so it might not hurt to have this)
- [x] fix a bug where `PayloadActionCreator<any>` becomes `ActionCreatorWithoutPayload` which was a regression introduced in #273 (also opened https://github.com/joonhocho/tsdef/pull/4 )
- [x] type `_ActionCreatorWithPreparedPayload` is now marked `@internal` (was `ActionCreatorWithPreparedPayload` before #273, since we renamed it anyway might as well hide it completely)
- [x] `@internal` types will be stripped from the `dist/typings.d.ts` file
- [x] document ALL types
- [x] add release tags (@public or @internal) to all types
- [x] add a type test that successfully wraps `createSlice`
- [x] ~~api-extractor trims too agressively (complete removal instead of "not export") - I'll have to see if that works out. (see https://github.com/microsoft/rushstack/issues/1664 )~~ (solved by manually exporting)
- [x] fix TS 3.3
- [x] add "Wrapping createSlice" chapter to the TS docs 
- [x] add "Defining the type of your initialState"  chapter to the TS docs


netlify[bot]: Deploy preview for *redux-starter-kit-docs* ready!

Built with commit 152984119645e44de2c9523ab3f81f1090619842

https://deploy-preview-290--redux-starter-kit-docs.netlify.com
codesandbox[bot]: This pull request is automatically built and testable in [CodeSandbox](https://codesandbox.io).

  To see build info of the built libraries, click [here](https://ci.codesandbox.io/status/reduxjs/redux-toolkit/pr/290/builds/5650) or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 152984119645e44de2c9523ab3f81f1090619842:

|Sandbox| Source |
|--|--|
|[snowy-dew-uioqn](https://codesandbox.io/s/snowy-dew-uioqn)| Configuration |
|[smoosh-browser-6ftmj](https://codesandbox.io/s/smoosh-browser-6ftmj)| Configuration |
|[rsk-github-issues-example](https://codesandbox.io/s/rsk-github-issues-example-b7dyk)| Configuration |

markerikson: Your ability to crank out TS improvements continues to amaze me :)

No specific feedback from me on the changes, but as usual I still don't know quite enough to provide much feedback here anyway.  

Do you want to try to get the other type doc changes in here too, or save those for later?
phryneas: > Your ability to crank out TS improvements continues to amaze me :)

This project is a wonderful learning experience, but it kills time like nothing else. I think i've started this Refactor over four or five times, each time putting in like 3-5 hours and then throwing everything away because it just wasn't working out.
So in the end, it just comes down to trial, error and my determination to bash my head against it until I find out how it works ;)

> Do you want to try to get the other type doc changes in here too, or save those for later?

I'm planning on doing everything in this PR, now that I already mixed different things in here. 
We'll probably have to wait for https://github.com/microsoft/rushstack/issues/1664 anyways and I need to find out why this doesn't work with TS3.3 again :woman_shrugging: 
phryneas: So it seems that relying on `@internal` won't be a possibility for us to exclude certain types from the dts-rollup (although it has a nice documenting effect when reading the source :smile: ). Which means I'll have to replace the `export * from ...` in `index.ts` with explicit export statements.
@markerikson would that be okay with you? I believe that might even help bundlers to do tree-shaking, although that's only a gut feeling.

The alternative would be to move the type to a different file where nothing is exported from, but right now I'd say that the type is in the file it belongs to.
markerikson: Yeah, if that's necessary to keep internal types from leaking, we can do that.
phryneas: Okay, that's it for today. All that's left is fixing TS3.3 - I hope that's gonna work out, but I'll leave that problem for "future me" :smile: 
phryneas: So, to make this work with TS <3.4, unfortunately I had to move `ValidateSliceCaseReducers` out of `SliceCaseReducers` (I renamed that one from `SliceCaseReducerDefintions`) again, because the `generic that extends itself to restrict itself` tactic seems not to be working in older TS versions.
This means, we have one more exported type: `ValidateSliceCaseReducers`.

But all in all, given that `SliceCaseReducers` is now a normal type and we aren't going over that "anoymous `PayloadActions` type" that was in there that was absolutely confusing, I think this whole refactor still has some good value and we can actually expose those types in good consciousness.
phryneas: Oh, seriously? Now TS is acting up, only in 3.4 :roll_eyes: 

`Draft<GenericState<T>>` is not compatible with `GenericState<T>`. Suure.
phryneas: Yay, we're all green, without dirty hacks. 

I was almost rage-quitting there o_O
markerikson: No immediate complaints about the TS stuff, but my eyes also mostly glazed over, so take it as you will :)

Saw a couple possible comment typos, suggested a rewording, and it'd be nice to see the "generic slice" example in the docs, but other than that looks okay.
phryneas: Added a "Wrapping `createSlice`" chapter to the TS docs. While I was at it, I also added a "Defining the type of your `initialState`" chapter, as that was something of importance we had not mentioned before.

Patch:
diff --git a/.travis.yml b/.travis.yml
index 716824d8..651a9628 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,6 +2,7 @@ language: node_js
 node_js: node
 env:
   - TYPESCRIPT_VERSION=rc
+  - TYPESCRIPT_VERSION=3.7
   - TYPESCRIPT_VERSION=3.6
   - TYPESCRIPT_VERSION=3.5
   - TYPESCRIPT_VERSION=3.4
diff --git a/api-extractor.json b/api-extractor.json
index c005b5ee..d6e9fa02 100644
--- a/api-extractor.json
+++ b/api-extractor.json
@@ -324,14 +324,9 @@
         "logLevel": "warning"
         // "addToApiReportFile": false
       },
-
-      "ae-missing-release-tag": {
-        "logLevel": "none",
-        "addToApiReportFile": true
-      },
       "ae-forgotten-export": {
         "logLevel": "none",
-        "addToApiReportFile": true
+        "addToApiReportFile": false
       }
       //
       // . . .
diff --git a/docs/usage/usage-with-typescript.md b/docs/usage/usage-with-typescript.md
index d053c637..89a325b6 100644
--- a/docs/usage/usage-with-typescript.md
+++ b/docs/usage/usage-with-typescript.md
@@ -195,6 +195,26 @@ createSlice({
 })
 ```
 
+### Defining the type of your `initialState`
+
+You might have noticed that it is not a good idea to pass your `SliceState` type as a generic to `createSlice`. This is due to the fact that in almost all cases, follow-up generic parameters to `createSlice` need to be inferred, and TypeScript cannot mix explicit declaration and inference of generic types within the same "generic block".
+
+Instead, you can use the construct `initialState: myInitialState as SliceState`.
+
+```ts
+type SliceState = { state: 'loading' } | { state: 'finished'; data: string }
+
+createSlice({
+  name: 'test',
+  initialState: { state: 'loading' } as SliceState,
+  reducers: {
+    // ...
+  }
+})
+```
+
+which will result in a `Slice<SliceState, ...>`.
+
 ### On the "type" property of slice action Reducers
 
 As TS cannot combine two string literals (`slice.name` and the key of `actionMap`) into a new literal, all actionCreators created by createSlice are of type 'string'. This is usually not a problem, as these types are only rarely used as literals.
@@ -222,3 +242,62 @@ If you actually _need_ that type, unfortunately there is no other way than manua
 ### Type safety with `extraReducers`
 
 Like in `createReducer`, the `extraReducers` map object is not easy to fully type. So, like with `createReducer`, you may also use the "builder callback" approach for defining the reducer object argument. See [the `createReducer` section above](#createreducer) for an example.
+
+### Wrapping `createSlice`
+
+If you need to reuse reducer logic, it is common to write ["higher-order reducers"](https://redux.js.org/recipes/structuring-reducers/reusing-reducer-logic#customizing-behavior-with-higher-order-reducers) that wrap a reducer function with additional common behavior. This can be done with `createSlice` as well, but due to the complexity of the types for `createSlice`, you have to use the `SliceCaseReducers` and `ValidateSliceCaseReducers` types in a very specific way.
+
+Here is an example of such a "generic" wrapped `createSlice` call:
+
+```ts
+interface GenericState<T> {
+  data?: T
+  status: 'loading' | 'finished' | 'error'
+}
+
+const createGenericSlice = <
+  T,
+  Reducers extends SliceCaseReducers<GenericState<T>>
+>({
+  name = '',
+  initialState,
+  reducers
+}: {
+  name: string
+  initialState: GenericState<T>
+  reducers: ValidateSliceCaseReducers<GenericState<T>, Reducers>
+}) => {
+  return createSlice({
+    name,
+    initialState,
+    reducers: {
+      start(state) {
+        state.status = 'loading'
+      },
+      /**
+       * If you want to write to values of the state that depend on the generic
+       * (in this case: `state.data`, which is T), you might need to specify the
+       * State type manually here, as it defaults to `Draft<GenericState<T>>`,
+       * which can sometimes be problematic with yet-unresolved generics.
+       * This is a general problem when working with immer's Draft type and generics.
+       */
+      success(state: GenericState<T>, action: PayloadAction<T>) {
+        state.data = action.payload
+        state.status = 'finished'
+      },
+      ...reducers
+    }
+  })
+}
+
+const wrappedSlice = createGenericSlice({
+  name: 'test',
+  initialState: { status: 'loading' } as GenericState<string>,
+  reducers: {
+    magic(state) {
+      state.status = 'finished'
+      state.data = 'hocus pocus'
+    }
+  }
+})
+```
diff --git a/etc/redux-toolkit.api.md b/etc/redux-toolkit.api.md
index 46f470eb..af6ce26d 100644
--- a/etc/redux-toolkit.api.md
+++ b/etc/redux-toolkit.api.md
@@ -18,100 +18,69 @@ import { Store } from 'redux';
 import { StoreEnhancer } from 'redux';
 import { ThunkDispatch } from 'redux-thunk';
 
-// Warning: (ae-forgotten-export) The symbol "BaseActionCreator" needs to be exported by the entry point index.d.ts
-// Warning: (ae-missing-release-tag) "ActionCreatorWithNonInferrablePayload" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
-// @public (undocumented)
+// @public
 export interface ActionCreatorWithNonInferrablePayload<T extends string = string> extends BaseActionCreator<unknown, T> {
-    // (undocumented)
     <PT extends unknown>(payload: PT): PayloadAction<PT, T>;
 }
 
-// Warning: (ae-missing-release-tag) "ActionCreatorWithOptionalPayload" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
-// @public (undocumented)
+// @public
 export interface ActionCreatorWithOptionalPayload<P, T extends string = string> extends BaseActionCreator<P, T> {
-    // (undocumented)
     (payload?: undefined): PayloadAction<undefined, T>;
-    // Warning: (ae-forgotten-export) The symbol "Diff" needs to be exported by the entry point index.d.ts
-    //
-    // (undocumented)
     <PT extends Diff<P, undefined>>(payload?: PT): PayloadAction<PT, T>;
 }
 
-// Warning: (ae-missing-release-tag) "ActionCreatorWithoutPayload" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
-// @public (undocumented)
+// @public
 export interface ActionCreatorWithoutPayload<T extends string = string> extends BaseActionCreator<undefined, T> {
-    // (undocumented)
     (): PayloadAction<undefined, T>;
 }
 
-// Warning: (ae-missing-release-tag) "ActionCreatorWithPayload" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
-// @public (undocumented)
+// @public
 export interface ActionCreatorWithPayload<P, T extends string = string> extends BaseActionCreator<P, T> {
-    // (undocumented)
     <PT extends P>(payload: PT): PayloadAction<PT, T>;
-    // (undocumented)
     (payload: P): PayloadAction<P, T>;
 }
 
-// Warning: (ae-missing-release-tag) "ActionCreatorWithPreparedPayload" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
-// @public (undocumented)
+// @public
 export interface ActionCreatorWithPreparedPayload<Args extends unknown[], P, T extends string = string, E = never, M = never> extends BaseActionCreator<P, T, M, E> {
-    // (undocumented)
     (...args: Args): PayloadAction<P, T, M, E>;
 }
 
-// Warning: (ae-missing-release-tag) "_ActionCreatorWithPreparedPayload" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
-// @public (undocumented)
-export type _ActionCreatorWithPreparedPayload<PA extends PrepareAction<any> | void, T extends string = string> = PA extends PrepareAction<infer P> ? ActionCreatorWithPreparedPayload<Parameters<PA>, P, T, ReturnType<PA> extends {
-    error: infer E;
-} ? E : never, ReturnType<PA> extends {
-    meta: infer M;
-} ? M : never> : void;
-
-// Warning: (ae-missing-release-tag) "ActionReducerMapBuilder" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
 // @public
 export interface ActionReducerMapBuilder<State> {
-    // Warning: (ae-forgotten-export) The symbol "TypedActionCreator" needs to be exported by the entry point index.d.ts
     addCase<ActionCreator extends TypedActionCreator<string>>(actionCreator: ActionCreator, reducer: CaseReducer<State, ReturnType<ActionCreator>>): ActionReducerMapBuilder<State>;
     addCase<Type extends string, A extends Action<Type>>(type: Type, reducer: CaseReducer<State, A>): ActionReducerMapBuilder<State>;
 }
 
-// Warning: (ae-missing-release-tag) "Actions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
-// @public
+// @public @deprecated
 export type Actions<T extends keyof any = string> = Record<T, Action>;
 
-// Warning: (ae-missing-release-tag) "CaseReducer" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
 // @public
 export type CaseReducer<S = any, A extends Action = AnyAction> = (state: Draft<S>, action: A) => S | void;
 
-// Warning: (ae-missing-release-tag) "CaseReducers" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
 // @public
+export type CaseReducerActions<CaseReducers extends SliceCaseReducers<any>> = {
+    [Type in keyof CaseReducers]: CaseReducers[Type] extends {
+        prepare: any;
+    } ? ActionCreatorForCaseReducerWithPrepare<CaseReducers[Type]> : ActionCreatorForCaseReducer<CaseReducers[Type]>;
+};
+
+// @public @deprecated
 export type CaseReducers<S, AS extends Actions> = {
     [T in keyof AS]: AS[T] extends Action ? CaseReducer<S, AS[T]> : void;
 };
 
-// Warning: (ae-missing-release-tag) "ConfigureEnhancersCallback" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
-// @public (undocumented)
+// @public
+export type CaseReducerWithPrepare<State, Action extends PayloadAction> = {
+    reducer: CaseReducer<State, Action>;
+    prepare: PrepareAction<Action['payload']>;
+};
+
+// @public
 export type ConfigureEnhancersCallback = (defaultEnhancers: StoreEnhancer[]) => StoreEnhancer[];
 
-// Warning: (ae-missing-release-tag) "configureStore" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
 // @public
 export function configureStore<S = any, A extends Action = AnyAction>(options: ConfigureStoreOptions<S, A>): EnhancedStore<S, A>;
 
-// Warning: (ae-missing-release-tag) "ConfigureStoreOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
 // @public
 export interface ConfigureStoreOptions<S = any, A extends Action = AnyAction> {
     devTools?: boolean | EnhancerOptions;
@@ -121,20 +90,14 @@ export interface ConfigureStoreOptions<S = any, A extends Action = AnyAction> {
     reducer: Reducer<S, A> | ReducersMapObject<S, A>;
 }
 
-// Warning: (ae-missing-release-tag) "createAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-// Warning: (ae-missing-release-tag) "createAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
 // @public
 export function createAction<P = void, T extends string = string>(type: T): PayloadActionCreator<P, T>;
 
-// @public (undocumented)
+// @public
 export function createAction<PA extends PrepareAction<any>, T extends string = string>(type: T, prepareAction: PA): PayloadActionCreator<ReturnType<PA>['payload'], T, PA>;
 
 export { createNextState }
 
-// Warning: (ae-missing-release-tag) "createReducer" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-// Warning: (ae-missing-release-tag) "createReducer" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
 // @public
 export function createReducer<S, CR extends CaseReducers<S, any> = CaseReducers<S, any>>(initialState: S, actionsMap: CR): Reducer<S>;
 
@@ -143,61 +106,38 @@ export function createReducer<S>(initialState: S, builderCallback: (builder: Act
 
 export { createSelector }
 
-// Warning: (ae-missing-release-tag) "createSerializableStateInvariantMiddleware" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
 // @public
 export function createSerializableStateInvariantMiddleware(options?: SerializableStateInvariantMiddlewareOptions): Middleware;
 
-// Warning: (ae-forgotten-export) The symbol "SliceCaseReducerDefinitions" needs to be exported by the entry point index.d.ts
-// Warning: (ae-forgotten-export) The symbol "RestrictCaseReducerDefinitionsToMatchReducerAndPrepare" needs to be exported by the entry point index.d.ts
-// Warning: (ae-missing-release-tag) "createSlice" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
 // @public
-export function createSlice<State, CaseReducers extends SliceCaseReducerDefinitions<State, any>>(options: CreateSliceOptions<State, CaseReducers> & RestrictCaseReducerDefinitionsToMatchReducerAndPrepare<State, CaseReducers>): Slice<State, CaseReducers>;
+export function createSlice<State, CaseReducers extends SliceCaseReducers<State>>(options: CreateSliceOptions<State, CaseReducers>): Slice<State, CaseReducers>;
 
-// Warning: (ae-missing-release-tag) "CreateSliceOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
 // @public
-export interface CreateSliceOptions<State = any, CR extends SliceCaseReducerDefinitions<State, any> = SliceCaseReducerDefinitions<State, any>> {
-    // Warning: (ae-forgotten-export) The symbol "NoInfer" needs to be exported by the entry point index.d.ts
+export interface CreateSliceOptions<State = any, CR extends SliceCaseReducers<State> = SliceCaseReducers<State>> {
     extraReducers?: CaseReducers<NoInfer<State>, any> | ((builder: ActionReducerMapBuilder<NoInfer<State>>) => void);
     initialState: State;
     name: string;
-    reducers: CR;
+    reducers: ValidateSliceCaseReducers<State, CR>;
 }
 
-// Warning: (ae-missing-release-tag) "EnhancedStore" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
 // @public
 export interface EnhancedStore<S = any, A extends Action = AnyAction> extends Store<S, A> {
     // (undocumented)
     dispatch: ThunkDispatch<S, any, A>;
 }
 
-// Warning: (ae-forgotten-export) The symbol "NonSerializableValue" needs to be exported by the entry point index.d.ts
-// Warning: (ae-missing-release-tag) "findNonSerializableValue" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
 // @public (undocumented)
 export function findNonSerializableValue(value: unknown, path?: ReadonlyArray<string>, isSerializable?: (value: unknown) => boolean, getEntries?: (value: unknown) => [string, any][]): NonSerializableValue | false;
 
-// Warning: (ae-forgotten-export) The symbol "GetDefaultMiddlewareOptions" needs to be exported by the entry point index.d.ts
-// Warning: (ae-missing-release-tag) "getDefaultMiddleware" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
 // @public
 export function getDefaultMiddleware<S = any>(options?: GetDefaultMiddlewareOptions): Middleware<{}, S>[];
 
-// Warning: (ae-missing-release-tag) "getType" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
 // @public
 export function getType<T extends string>(actionCreator: PayloadActionCreator<any, T>): T;
 
-// Warning: (ae-missing-release-tag) "isPlain" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
 // @public
 export function isPlain(val: any): boolean;
 
-// Warning: (ae-missing-release-tag) "PayloadAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
 // @public
 export type PayloadAction<P = void, T extends string = string, M = never, E = never> = {
     payload: P;
@@ -208,18 +148,10 @@ export type PayloadAction<P = void, T extends string = string, M = never, E = ne
     error: E;
 });
 
-// Warning: (ae-forgotten-export) The symbol "IfPrepareActionMethodProvided" needs to be exported by the entry point index.d.ts
-// Warning: (ae-forgotten-export) The symbol "IsUnknownOrNonInferrable" needs to be exported by the entry point index.d.ts
-// Warning: (ae-forgotten-export) The symbol "IfVoid" needs to be exported by the entry point index.d.ts
-// Warning: (ae-forgotten-export) The symbol "IfMaybeUndefined" needs to be exported by the entry point index.d.ts
-// Warning: (ae-missing-release-tag) "PayloadActionCreator" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
 // @public
-export type PayloadActionCreator<P = void, T extends string = string, PA extends PrepareAction<P> | void = void> = IfPrepareActionMethodProvided<PA, _ActionCreatorWithPreparedPayload<PA, T>, IsUnknownOrNonInferrable<P, ActionCreatorWithNonInferrablePayload<T>, IfVoid<P, ActionCreatorWithoutPayload<T>, IfMaybeUndefined<P, ActionCreatorWithOptionalPayload<P, T>, ActionCreatorWithPayload<P, T>>>>>;
+export type PayloadActionCreator<P = void, T extends string = string, PA extends PrepareAction<P> | void = void> = IfPrepareActionMethodProvided<PA, _ActionCreatorWithPreparedPayload<PA, T>, IsAny<P, ActionCreatorWithPayload<any, T>, IsUnknownOrNonInferrable<P, ActionCreatorWithNonInferrablePayload<T>, IfVoid<P, ActionCreatorWithoutPayload<T>, IfMaybeUndefined<P, ActionCreatorWithOptionalPayload<P, T>, ActionCreatorWithPayload<P, T>>>>>>;
 
-// Warning: (ae-missing-release-tag) "PrepareAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
-// @public (undocumented)
+// @public
 export type PrepareAction<P> = ((...args: any[]) => {
     payload: P;
 }) | ((...args: any[]) => {
@@ -234,8 +166,6 @@ export type PrepareAction<P> = ((...args: any[]) => {
     error: any;
 });
 
-// Warning: (ae-missing-release-tag) "SerializableStateInvariantMiddlewareOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
 // @public
 export interface SerializableStateInvariantMiddlewareOptions {
     getEntries?: (value: any) => [string, any][];
@@ -243,28 +173,35 @@ export interface SerializableStateInvariantMiddlewareOptions {
     isSerializable?: (value: any) => boolean;
 }
 
-// Warning: (ae-forgotten-export) The symbol "PayloadActions" needs to be exported by the entry point index.d.ts
-// Warning: (ae-missing-release-tag) "Slice" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
-// @public (undocumented)
-export interface Slice<State = any, CaseReducers extends SliceCaseReducerDefinitions<State, PayloadActions> = {
-    [key: string]: any;
-}> {
-    // Warning: (ae-forgotten-export) The symbol "CaseReducerActions" needs to be exported by the entry point index.d.ts
+// @public
+export interface Slice<State = any, CaseReducers extends SliceCaseReducers<State> = SliceCaseReducers<State>> {
     actions: CaseReducerActions<CaseReducers>;
-    // Warning: (ae-forgotten-export) The symbol "SliceDefinedCaseReducers" needs to be exported by the entry point index.d.ts
-    //
-    // (undocumented)
-    caseReducers: SliceDefinedCaseReducers<CaseReducers, State>;
+    caseReducers: SliceDefinedCaseReducers<CaseReducers>;
     name: string;
     reducer: Reducer<State>;
 }
 
-// Warning: (ae-missing-release-tag) "SliceActionCreator" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
 // @public @deprecated
 export type SliceActionCreator<P> = PayloadActionCreator<P>;
 
+// @public
+export type SliceCaseReducers<State> = {
+    [K: string]: CaseReducer<State, PayloadAction<any>> | CaseReducerWithPrepare<State, PayloadAction<any>>;
+};
+
+// @public
+export type ValidateSliceCaseReducers<S, ACR extends SliceCaseReducers<S>> = ACR & {
+    [P in keyof ACR]: ACR[P] extends {
+        reducer(s: S, action?: {
+            payload: infer O;
+        }): any;
+    } ? {
+        prepare(...a: never[]): {
+            payload: O;
+        };
+    } : {};
+};
+
 
 export * from "redux";
 
diff --git a/src/configureStore.ts b/src/configureStore.ts
index 33b2e04d..560159e9 100644
--- a/src/configureStore.ts
+++ b/src/configureStore.ts
@@ -23,12 +23,19 @@ import { getDefaultMiddleware } from './getDefaultMiddleware'
 
 const IS_PRODUCTION = process.env.NODE_ENV === 'production'
 
+/**
+ * Callback function type, to be used in `ConfigureStoreOptions.enhancers`
+ *
+ * @public
+ */
 export type ConfigureEnhancersCallback = (
   defaultEnhancers: StoreEnhancer[]
 ) => StoreEnhancer[]
 
 /**
  * Options for `configureStore()`.
+ *
+ * @public
  */
 export interface ConfigureStoreOptions<S = any, A extends Action = AnyAction> {
   /**
@@ -78,9 +85,14 @@ export interface ConfigureStoreOptions<S = any, A extends Action = AnyAction> {
 /**
  * A Redux store returned by `configureStore()`. Supports dispatching
  * side-effectful _thunks_ in addition to plain actions.
+ *
+ * @public
  */
 export interface EnhancedStore<S = any, A extends Action = AnyAction>
   extends Store<S, A> {
+  /**
+   * @inheritdoc
+   */
   dispatch: ThunkDispatch<S, any, A>
 }
 
@@ -89,6 +101,8 @@ export interface EnhancedStore<S = any, A extends Action = AnyAction>
  *
  * @param config The store configuration.
  * @returns A configured Redux store.
+ *
+ * @public
  */
 export function configureStore<S = any, A extends Action = AnyAction>(
   options: ConfigureStoreOptions<S, A>
diff --git a/src/createAction.ts b/src/createAction.ts
index 72f55cd6..73c32ef0 100644
--- a/src/createAction.ts
+++ b/src/createAction.ts
@@ -1,5 +1,10 @@
 import { Action } from 'redux'
-import { IsUnknownOrNonInferrable, IfMaybeUndefined, IfVoid } from './tsHelpers'
+import {
+  IsUnknownOrNonInferrable,
+  IfMaybeUndefined,
+  IfVoid,
+  IsAny
+} from './tsHelpers'
 
 /**
  * An action with a string type and an associated payload. This is the
@@ -9,6 +14,8 @@ import { IsUnknownOrNonInferrable, IfMaybeUndefined, IfVoid } from './tsHelpers'
  * @template T the type used for the action type.
  * @template M The type of the action's meta (optional)
  * @template E The type of the action's error (optional)
+ *
+ * @public
  */
 export type PayloadAction<
   P = void,
@@ -29,12 +36,24 @@ export type PayloadAction<
         error: E
       })
 
+/**
+ * A "prepare" method to be used as the second parameter of `createAction`.
+ * Takes any number of arguments and returns a Flux Standard Action without
+ * type (will be added later) that *must* contain a payload (might be undefined).
+ *
+ * @public
+ */
 export type PrepareAction<P> =
   | ((...args: any[]) => { payload: P })
   | ((...args: any[]) => { payload: P; meta: any })
   | ((...args: any[]) => { payload: P; error: any })
   | ((...args: any[]) => { payload: P; meta: any; error: any })
 
+/**
+ * Internal version of `ActionCreatorWithPreparedPayload`. Not to be used externally.
+ *
+ * @internal
+ */
 export type _ActionCreatorWithPreparedPayload<
   PA extends PrepareAction<any> | void,
   T extends string = string
@@ -56,11 +75,29 @@ export type _ActionCreatorWithPreparedPayload<
     >
   : void
 
+/**
+ * Basic type for all action creators.
+ *
+ * @inheritdoc {redux#ActionCreator}
+ */
 interface BaseActionCreator<P, T extends string, M = never, E = never> {
   type: T
   match(action: Action<unknown>): action is PayloadAction<P, T, M, E>
 }
 
+/**
+ * An action creator that takes multiple arguments that are passed
+ * to a `PrepareAction` method to create the final Action.
+ * @typeParam Args arguments for the action creator function
+ * @typeParam P `payload` type
+ * @typeParam T `type` name
+ * @typeParam E optional `error` type
+ * @typeParam M optional `meta` type
+ *
+ * @inheritdoc {redux#ActionCreator}
+ *
+ * @public
+ */
 export interface ActionCreatorWithPreparedPayload<
   Args extends unknown[],
   P,
@@ -68,34 +105,99 @@ export interface ActionCreatorWithPreparedPayload<
   E = never,
   M = never
 > extends BaseActionCreator<P, T, M, E> {
+  /**
+   * Calling this {@link redux#ActionCreator} with `Args` will return
+   * an Action with a payload of type `P` and (depending on the `PrepareAction`
+   * method used) a `meta`- and `error` property of types `M` and `E` respectively.
+   */
   (...args: Args): PayloadAction<P, T, M, E>
 }
 
+/**
+ * An action creator of type `T` that takes an optional payload of type `P`.
+ *
+ * @inheritdoc {redux#ActionCreator}
+ *
+ * @public
+ */
 export interface ActionCreatorWithOptionalPayload<P, T extends string = string>
   extends BaseActionCreator<P, T> {
+  /**
+   * Calling this {@link redux#ActionCreator} without arguments will
+   * return a {@link PayloadAction} of type `T` with a payload of `undefined`
+   */
   (payload?: undefined): PayloadAction<undefined, T>
+  /**
+   * Calling this {@link redux#ActionCreator} with an argument will
+   * return a {@link PayloadAction} of type `T` with a payload of `P`
+   */
   <PT extends Diff<P, undefined>>(payload?: PT): PayloadAction<PT, T>
 }
 
+/**
+ * An action creator of type `T` that takes no payload.
+ *
+ * @inheritdoc {redux#ActionCreator}
+ *
+ * @public
+ */
 export interface ActionCreatorWithoutPayload<T extends string = string>
   extends BaseActionCreator<undefined, T> {
+  /**
+   * Calling this {@link redux#ActionCreator} will
+   * return a {@link PayloadAction} of type `T` with a payload of `undefined`
+   */
   (): PayloadAction<undefined, T>
 }
 
+/**
+ * An action creator of type `T` that requires a payload of type P.
+ *
+ * @inheritdoc {redux#ActionCreator}
+ *
+ * @public
+ */
 export interface ActionCreatorWithPayload<P, T extends string = string>
   extends BaseActionCreator<P, T> {
+  /**
+   * Calling this {@link redux#ActionCreator} with an argument will
+   * return a {@link PayloadAction} of type `T` with a payload of `P`
+   * If possible, `P` will be narrowed down to the exact type of the payload argument.
+   */
   <PT extends P>(payload: PT): PayloadAction<PT, T>
+  /**
+   * Calling this {@link redux#ActionCreator} with an argument will
+   * return a {@link PayloadAction} of type `T` with a payload of `P`
+   */
   (payload: P): PayloadAction<P, T>
 }
 
+/**
+ * An action creator of type `T` whose `payload` type could not be inferred. Accepts everything as `payload`.
+ *
+ * @inheritdoc {redux#ActionCreator}
+ *
+ * @public
+ */
 export interface ActionCreatorWithNonInferrablePayload<
   T extends string = string
 > extends BaseActionCreator<unknown, T> {
+  /**
+   * Calling this {@link redux#ActionCreator} with an argument will
+   * return a {@link PayloadAction} of type `T` with a payload
+   * of exactly the type of the argument.
+   */
   <PT extends unknown>(payload: PT): PayloadAction<PT, T>
 }
 
 /**
  * An action creator that produces actions with a `payload` attribute.
+ *
+ * @typeParam P the `payload` type
+ * @typeParam T the `type` of the resulting action
+ * @typeParam PA if the resulting action is preprocessed by a `prepare` method, the signature of said method.
+ *
+ * @public
  */
 export type PayloadActionCreator<
   P = void,
@@ -105,19 +207,23 @@ export type PayloadActionCreator<
   PA,
   _ActionCreatorWithPreparedPayload<PA, T>,
   // else
-  IsUnknownOrNonInferrable<
+  IsAny<
     P,
-    ActionCreatorWithNonInferrablePayload<T>,
-    // else
-    IfVoid<
+    ActionCreatorWithPayload<any, T>,
+    IsUnknownOrNonInferrable<
       P,
-      ActionCreatorWithoutPayload<T>,
+      ActionCreatorWithNonInferrablePayload<T>,
       // else
-      IfMaybeUndefined<
+      IfVoid<
         P,
-        ActionCreatorWithOptionalPayload<P, T>,
+        ActionCreatorWithoutPayload<T>,
         // else
-        ActionCreatorWithPayload<P, T>
+        IfMaybeUndefined<
+          P,
+          ActionCreatorWithOptionalPayload<P, T>,
+          // else
+          ActionCreatorWithPayload<P, T>
+        >
       >
     >
   >
@@ -133,12 +239,26 @@ export type PayloadActionCreator<
  * @param type The action type to use for created actions.
  * @param prepare (optional) a method that takes any number of arguments and returns { payload } or { payload, meta }.
  *                If this is given, the resulting action creator will pass it's arguments to this method to calculate payload & meta.
+ *
+ * @public
  */
-
 export function createAction<P = void, T extends string = string>(
   type: T
 ): PayloadActionCreator<P, T>
 
+/**
+ * A utility function to create an action creator for the given action type
+ * string. The action creator accepts a single argument, which will be included
+ * in the action object as a field called payload. The action creator function
+ * will also have its toString() overriden so that it returns the action type,
+ * allowing it to be used in reducer logic that is looking for that action type.
+ *
+ * @param type The action type to use for created actions.
+ * @param prepare (optional) a method that takes any number of arguments and returns { payload } or { payload, meta }.
+ *                If this is given, the resulting action creator will pass it's arguments to this method to calculate payload & meta.
+ *
+ * @public
+ */
 export function createAction<
   PA extends PrepareAction<any>,
   T extends string = string
@@ -182,6 +302,8 @@ export function createAction(type: string, prepareAction?: Function): any {
  *
  * @param action The action creator whose action type to get.
  * @returns The action type used by the action creator.
+ *
+ * @public
  */
 export function getType<T extends string>(
   actionCreator: PayloadActionCreator<any, T>
diff --git a/src/createReducer.ts b/src/createReducer.ts
index 6c3d16c8..87232792 100644
--- a/src/createReducer.ts
+++ b/src/createReducer.ts
@@ -7,6 +7,11 @@ import {
 
 /**
  * Defines a mapping from action types to corresponding action object shapes.
+ *
+ * @deprecated This should not be used manually - it is only used for internal
+ *             inference purposes and should not have any further value.
+ *             It might be removed in the future.
+ * @public
  */
 export type Actions<T extends keyof any = string> = Record<T, Action>
 
@@ -23,6 +28,8 @@ export type Actions<T extends keyof any = string> = Record<T, Action>
  * cause the store state to be mutated directly; instead, thanks to
  * [immer](https://github.com/mweststrate/immer), the mutations are
  * translated to copy operations that result in a new state.
+ *
+ * @public
  */
 export type CaseReducer<S = any, A extends Action = AnyAction> = (
   state: Draft<S>,
@@ -31,6 +38,12 @@ export type CaseReducer<S = any, A extends Action = AnyAction> = (
 
 /**
  * A mapping from action types to case reducers for `createReducer()`.
+ *
+ * @deprecated This should not be used manually - it is only used
+ *             for internal inference purposes and using it manually
+ *             would lead to type erasure.
+ *             It might be removed in the future.
+ * @public
  */
 export type CaseReducers<S, AS extends Actions> = {
   [T in keyof AS]: AS[T] extends Action ? CaseReducer<S, AS[T]> : void
@@ -51,6 +64,8 @@ export type CaseReducers<S, AS extends Actions> = {
  * @param initialState The initial state to be returned by the reducer.
  * @param actionsMap A mapping from action types to action-type-specific
  *   case reducers.
+ *
+ * @public
  */
 export function createReducer<
   S,
@@ -70,6 +85,8 @@ export function createReducer<
  * @param initialState The initial state to be returned by the reducer.
  * @param builderCallback A callback that receives a *builder* object to define
  *   case reducers via calls to `builder.addCase(actionCreatorOrType, reducer)`.
+ *
+ * @public
  */
 export function createReducer<S>(
   initialState: S,
diff --git a/src/createSlice.ts b/src/createSlice.ts
index 9c0dcdbb..6dfeefcd 100644
--- a/src/createSlice.ts
+++ b/src/createSlice.ts
@@ -17,14 +17,19 @@ import {
  * An action creator atttached to a slice.
  *
  * @deprecated please use PayloadActionCreator directly
+ *
+ * @public
  */
 export type SliceActionCreator<P> = PayloadActionCreator<P>
 
+/**
+ * The return value of `createSlice`
+ *
+ * @public
+ */
 export interface Slice<
   State = any,
-  CaseReducers extends SliceCaseReducerDefinitions<State, PayloadActions> = {
-    [key: string]: any
-  }
+  CaseReducers extends SliceCaseReducers<State> = SliceCaseReducers<State>
 > {
   /**
    * The slice name.
@@ -42,18 +47,21 @@ export interface Slice<
    */
   actions: CaseReducerActions<CaseReducers>
 
-  caseReducers: SliceDefinedCaseReducers<CaseReducers, State>
+  /**
+   * The individual case reducer functions that were passed in the `reducers` parameter.
+   * This enables reuse and testing if they were defined inline when calling `createSlice`.
+   */
+  caseReducers: SliceDefinedCaseReducers<CaseReducers>
 }
 
 /**
  * Options for `createSlice()`.
+ *
+ * @public
  */
 export interface CreateSliceOptions<
   State = any,
-  CR extends SliceCaseReducerDefinitions<
-    State,
-    any
-  > = SliceCaseReducerDefinitions<State, any>
+  CR extends SliceCaseReducers<State> = SliceCaseReducers<State>
 > {
   /**
    * The slice's name. Used to namespace the generated action types.
@@ -70,7 +78,7 @@ export interface CreateSliceOptions<
    * functions. For every action type, a matching action creator will be
    * generated using `createAction()`.
    */
-  reducers: CR
+  reducers: ValidateSliceCaseReducers<State, CR>
 
   /**
    * A mapping from action types to action-type-specific *case reducer*
@@ -84,98 +92,109 @@ export interface CreateSliceOptions<
     | ((builder: ActionReducerMapBuilder<NoInfer<State>>) => void)
 }
 
-type PayloadActions<Types extends keyof any = string> = Record<
-  Types,
-  PayloadAction
->
-
-type CaseReducerWithPrepare<State, Action extends PayloadAction> = {
+/**
+ * A CaseReducer with a `prepare` method.
+ *
+ * @public
+ */
+export type CaseReducerWithPrepare<State, Action extends PayloadAction> = {
   reducer: CaseReducer<State, Action>
   prepare: PrepareAction<Action['payload']>
 }
 
-type SliceCaseReducerDefinitions<State, PA extends PayloadActions> = {
-  [ActionType in keyof PA]:
-    | CaseReducer<State, PA[ActionType]>
-    | CaseReducerWithPrepare<State, PA[ActionType]>
+/**
+ * The type describing a slice's `reducers` option.
+ *
+ * @public
+ */
+export type SliceCaseReducers<State> = {
+  [K: string]:
+    | CaseReducer<State, PayloadAction<any>>
+    | CaseReducerWithPrepare<State, PayloadAction<any>>
 }
 
-type IfIsReducerFunctionWithoutAction<R, True, False = never> = R extends (
-  state: any
-) => any
-  ? True
-  : False
-type IfIsCaseReducerWithPrepare<R, True, False = never> = R extends {
-  prepare: Function
+/**
+ * Derives the slice's `actions` property from the `reducers` options
+ *
+ * @public
+ */
+export type CaseReducerActions<CaseReducers extends SliceCaseReducers<any>> = {
+  [Type in keyof CaseReducers]: CaseReducers[Type] extends { prepare: any }
+    ? ActionCreatorForCaseReducerWithPrepare<CaseReducers[Type]>
+    : ActionCreatorForCaseReducer<CaseReducers[Type]>
 }
-  ? True
-  : False
 
-type PayloadForReducer<R> = R extends (
+/**
+ * Get a `PayloadActionCreator` type for a passed `CaseReducerWithPrepare`
+ *
+ * @internal
+ */
+type ActionCreatorForCaseReducerWithPrepare<
+  CR extends { prepare: any }
+> = _ActionCreatorWithPreparedPayload<CR['prepare'], string>
+
+/**
+ * Get a `PayloadActionCreator` type for a passed `CaseReducer`
+ *
+ * @internal
+ */
+type ActionCreatorForCaseReducer<CR> = CR extends (
   state: any,
-  action: PayloadAction<infer P>
+  action: infer Action
 ) => any
-  ? P
-  : void
-type PrepareActionForReducer<R> = R extends { prepare: infer Prepare }
-  ? Prepare
-  : never
-
-type ActionForReducer<R, S> = R extends (
-  state: S,
-  action: PayloadAction<infer P>
-) => S
-  ? PayloadAction<P>
-  : R extends {
-      reducer(state: any, action: PayloadAction<infer P>): any
-    }
-  ? PayloadAction<P>
-  : unknown
-
-type CaseReducerActions<
-  CaseReducers extends SliceCaseReducerDefinitions<any, any>
-> = {
-  [Type in keyof CaseReducers]: IfIsCaseReducerWithPrepare<
-    CaseReducers[Type],
-    _ActionCreatorWithPreparedPayload<
-      PrepareActionForReducer<CaseReducers[Type]>
-    >,
-    // else
-    IfIsReducerFunctionWithoutAction<
-      CaseReducers[Type],
-      ActionCreatorWithoutPayload,
-      // else
-      PayloadActionCreator<PayloadForReducer<CaseReducers[Type]>>
-    >
-  >
-}
+  ? Action extends { payload: infer P }
+    ? PayloadActionCreator<P>
+    : ActionCreatorWithoutPayload
+  : ActionCreatorWithoutPayload
 
-type SliceDefinedCaseReducers<
-  CaseReducers extends SliceCaseReducerDefinitions<any, any>,
-  State = any
-> = {
-  [Type in keyof CaseReducers]: CaseReducer<
-    State,
-    ActionForReducer<CaseReducers[Type], State>
-  >
+/**
+ * Extracts the CaseReducers out of a `reducers` object, even if they are
+ * tested into a `CaseReducerWithPrepare`.
+ *
+ * @internal
+ */
+type SliceDefinedCaseReducers<CaseReducers extends SliceCaseReducers<any>> = {
+  [Type in keyof CaseReducers]: CaseReducers[Type] extends {
+    reducer: infer Reducer
+  }
+    ? Reducer
+    : CaseReducers[Type]
 }
 
+/**
+ * Helper type. Passes T out again, but boxes it in a way that it cannot
+ * "widen" the type by accident if it is a generic that should be inferred
+ * from elsewhere.
+ *
+ * @internal
+ */
 type NoInfer<T> = [T][T extends any ? 0 : never]
 
-type SliceCaseReducersCheck<S, ACR> = {
-  [P in keyof ACR]: ACR[P] extends {
-    reducer(s: S, action?: { payload: infer O }): any
-  }
-    ? {
-        prepare(...a: never[]): { payload: O }
-      }
-    : {}
-}
-
-type RestrictCaseReducerDefinitionsToMatchReducerAndPrepare<
+/**
+ * Used on a SliceCaseReducers object.
+ * Ensures that if a CaseReducer is a `CaseReducerWithPrepare`, that
+ * the `reducer` and the `prepare` function use the same type of `payload`.
+ *
+ * Might do additional such checks in the future.
+ *
+ * This type is only ever useful if you want to write your own wrapper around
+ * `createSlice`. Please don't use it otherwise!
+ *
+ * @public
+ */
+export type ValidateSliceCaseReducers<
   S,
-  CR extends SliceCaseReducerDefinitions<S, any>
-> = { reducers: SliceCaseReducersCheck<S, NoInfer<CR>> }
+  ACR extends SliceCaseReducers<S>
+> = ACR &
+  {
+    [P in keyof ACR]: ACR[P] extends {
+      reducer(s: S, action?: { payload: infer O }): any
+    }
+      ? {
+          prepare(...a: never[]): { payload: O }
+        }
+      : {}
+  }
 
 function getType(slice: string, actionKey: string): string {
   return `${slice}/${actionKey}`
@@ -188,19 +207,12 @@ function getType(slice: string, actionKey: string): string {
  * reducers and state.
  *
  * The `reducer` argument is passed to `createReducer()`.
+ *
+ * @public
  */
 export function createSlice<
   State,
-  CaseReducers extends SliceCaseReducerDefinitions<State, any>
->(
-  options: CreateSliceOptions<State, CaseReducers> &
-    RestrictCaseReducerDefinitionsToMatchReducerAndPrepare<State, CaseReducers>
-): Slice<State, CaseReducers>
-
-// internal definition is a little less restrictive
-export function createSlice<
-  State,
-  CaseReducers extends SliceCaseReducerDefinitions<State, any>
+  CaseReducers extends SliceCaseReducers<State>
 >(
   options: CreateSliceOptions<State, CaseReducers>
 ): Slice<State, CaseReducers> {
@@ -229,11 +241,11 @@ export function createSlice<
     let caseReducer: CaseReducer<State, any>
     let prepareCallback: PrepareAction<any> | undefined
 
-    if (typeof maybeReducerWithPrepare === 'function') {
-      caseReducer = maybeReducerWithPrepare
-    } else {
+    if ('reducer' in maybeReducerWithPrepare) {
       caseReducer = maybeReducerWithPrepare.reducer
       prepareCallback = maybeReducerWithPrepare.prepare
+    } else {
+      caseReducer = maybeReducerWithPrepare
     }
 
     sliceCaseReducersByName[reducerName] = caseReducer
diff --git a/src/getDefaultMiddleware.ts b/src/getDefaultMiddleware.ts
index 37d92599..284a7bb7 100644
--- a/src/getDefaultMiddleware.ts
+++ b/src/getDefaultMiddleware.ts
@@ -34,6 +34,8 @@ interface GetDefaultMiddlewareOptions {
  * `middleware` array but still keep the default set.
  *
  * @return The default middleware used by `configureStore()`.
+ *
+ * @public
  */
 export function getDefaultMiddleware<S = any>(
   options: GetDefaultMiddlewareOptions = {}
diff --git a/src/index.ts b/src/index.ts
index 015d0475..06187758 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -2,10 +2,61 @@ export * from 'redux'
 export { default as createNextState } from 'immer'
 export { createSelector } from 'reselect'
 
-export * from './configureStore'
-export * from './createAction'
-export * from './createReducer'
-export * from './createSlice'
-export * from './serializableStateInvariantMiddleware'
-export * from './getDefaultMiddleware'
-export { ActionReducerMapBuilder } from './mapBuilders'
+export {
+  // js
+  configureStore,
+  // types
+  ConfigureEnhancersCallback,
+  ConfigureStoreOptions,
+  EnhancedStore
+} from './configureStore'
+export {
+  // js
+  createAction,
+  getType,
+  // types
+  PayloadAction,
+  PayloadActionCreator,
+  ActionCreatorWithNonInferrablePayload,
+  ActionCreatorWithOptionalPayload,
+  ActionCreatorWithPayload,
+  ActionCreatorWithoutPayload,
+  ActionCreatorWithPreparedPayload,
+  PrepareAction
+} from './createAction'
+export {
+  // js
+  createReducer,
+  // types
+  Actions,
+  CaseReducer,
+  CaseReducers
+} from './createReducer'
+export {
+  // js
+  createSlice,
+  // types
+  CreateSliceOptions,
+  Slice,
+  CaseReducerActions,
+  SliceCaseReducers,
+  ValidateSliceCaseReducers,
+  CaseReducerWithPrepare,
+  SliceActionCreator
+} from './createSlice'
+export {
+  // js
+  createSerializableStateInvariantMiddleware,
+  findNonSerializableValue,
+  isPlain,
+  // types
+  SerializableStateInvariantMiddlewareOptions
+} from './serializableStateInvariantMiddleware'
+export {
+  // js
+  getDefaultMiddleware
+} from './getDefaultMiddleware'
+export {
+  // types
+  ActionReducerMapBuilder
+} from './mapBuilders'
diff --git a/src/mapBuilders.ts b/src/mapBuilders.ts
index 6b53d0af..6a0ea0ab 100644
--- a/src/mapBuilders.ts
+++ b/src/mapBuilders.ts
@@ -8,6 +8,8 @@ export interface TypedActionCreator<Type extends string> {
 
 /**
  * A builder for an action <-> reducer map.
+ *
+ * @public
  */
 export interface ActionReducerMapBuilder<State> {
   /**
diff --git a/src/serializableStateInvariantMiddleware.ts b/src/serializableStateInvariantMiddleware.ts
index eaae1a91..514fdc94 100644
--- a/src/serializableStateInvariantMiddleware.ts
+++ b/src/serializableStateInvariantMiddleware.ts
@@ -7,6 +7,8 @@ import { Middleware } from 'redux'
  * or `undefined`.
  *
  * @param val The value to check.
+ *
+ * @public
  */
 export function isPlain(val: any) {
   return (
@@ -25,6 +27,9 @@ interface NonSerializableValue {
   value: unknown
 }
 
+/**
+ * @public
+ */
 export function findNonSerializableValue(
   value: unknown,
   path: ReadonlyArray<string> = [],
@@ -75,6 +80,8 @@ export function findNonSerializableValue(
 
 /**
  * Options for `createSerializableStateInvariantMiddleware()`.
+ *
+ * @public
  */
 export interface SerializableStateInvariantMiddlewareOptions {
   /**
@@ -102,6 +109,8 @@ export interface SerializableStateInvariantMiddlewareOptions {
  * state, an error is printed to the console.
  *
  * @param options Middleware options.
+ *
+ * @public
  */
 export function createSerializableStateInvariantMiddleware(
   options: SerializableStateInvariantMiddlewareOptions = {}
diff --git a/src/tsHelpers.ts b/src/tsHelpers.ts
index 647d85f9..c31c5b07 100644
--- a/src/tsHelpers.ts
+++ b/src/tsHelpers.ts
@@ -1,23 +1,38 @@
-// taken from https://github.com/joonhocho/tsdef
-// return True if T is `any`, otherwise return False
+/**
+ * return True if T is `any`, otherwise return False
+ * taken from https://github.com/joonhocho/tsdef
+ *
+ * @internal
+ */
 export type IsAny<T, True, False = never> =
-  | True
-  | False extends (T extends never ? True : False)
-  ? True
-  : False
+  // test if we are going the left AND right path in the condition
+  true | false extends (T extends never ? true : false) ? True : False
 
-// taken from https://github.com/joonhocho/tsdef
-// return True if T is `unknown`, otherwise return False
+/**
+ * return True if T is `unknown`, otherwise return False
+ * taken from https://github.com/joonhocho/tsdef
+ *
+ * @internal
+ */
 export type IsUnknown<T, True, False = never> = unknown extends T
   ? IsAny<T, False, True>
   : False
 
+/**
+ * @internal
+ */
 export type IfMaybeUndefined<P, True, False> = [undefined] extends [P]
   ? True
   : False
 
+/**
+ * @internal
+ */
 export type IfVoid<P, True, False> = [void] extends [P] ? True : False
 
+/**
+ * @internal
+ */
 export type IsEmptyObj<T, True, False = never> = T extends any
   ? keyof T extends never
     ? IsUnknown<T, False, IfMaybeUndefined<T, False, IfVoid<T, False, True>>>
@@ -29,13 +44,18 @@ export type IsEmptyObj<T, True, False = never> = T extends any
  * uses feature detection to detect TS version >= 3.5
  * * versions below 3.5 will return `{}` for unresolvable interference
  * * versions above will return `unknown`
- * */
+ *
+ * @internal
+ */
 export type AtLeastTS35<True, False> = [True, False][IsUnknown<
   ReturnType<<T>() => T>,
   0,
   1
 >]
 
+/**
+ * @internal
+ */
 export type IsUnknownOrNonInferrable<T, True, False> = AtLeastTS35<
   IsUnknown<T, True, False>,
   IsEmptyObj<T, True, IsUnknown<T, True, False>>


Test patch:
diff --git a/type-tests/files/createAction.typetest.ts b/type-tests/files/createAction.typetest.ts
index 8cb5fce6..702913a6 100644
--- a/type-tests/files/createAction.typetest.ts
+++ b/type-tests/files/createAction.typetest.ts
@@ -104,9 +104,9 @@ function expectType<T>(p: T): T {
     { type: 'action' }
   ) as PayloadActionCreator<number>
 
-  const actionCreator2: ActionCreator<PayloadAction<
-    number
-  >> = payloadActionCreator2
+  const actionCreator2: ActionCreator<
+    PayloadAction<number>
+  > = payloadActionCreator2
 }
 
 /* createAction() */
@@ -342,4 +342,8 @@ function expectType<T>(p: T): T {
       meta: 3 as 3
     }))
   )
+  const anyCreator = createAction<any>('')
+  expectType<ActionCreatorWithPayload<any>>(anyCreator)
+  type AnyPayload = ReturnType<typeof anyCreator>['payload']
+  expectType<IsAny<AnyPayload, true, false>>(true)
 }
diff --git a/type-tests/files/createSlice.typetest.ts b/type-tests/files/createSlice.typetest.ts
index fb20932f..7a1d7bb4 100644
--- a/type-tests/files/createSlice.typetest.ts
+++ b/type-tests/files/createSlice.typetest.ts
@@ -8,8 +8,10 @@ import {
   ActionCreatorWithNonInferrablePayload,
   ActionCreatorWithoutPayload,
   ActionCreatorWithPayload,
-  ActionCreatorWithPreparedPayload
+  ActionCreatorWithPreparedPayload,
+  SliceCaseReducers
 } from '../../src'
+import { ValidateSliceCaseReducers } from 'src/createSlice'
 
 function expectType<T>(t: T) {
   return t
@@ -312,3 +314,57 @@ function expectType<T>(t: T) {
     }
   })
 }
+
+/** Test: wrapping createSlice should be possible */
+{
+  interface GenericState<T> {
+    data?: T
+    status: 'loading' | 'finished' | 'error'
+  }
+
+  const createGenericSlice = <
+    T,
+    Reducers extends SliceCaseReducers<GenericState<T>>
+  >({
+    name = '',
+    initialState,
+    reducers
+  }: {
+    name: string
+    initialState: GenericState<T>
+    reducers: ValidateSliceCaseReducers<GenericState<T>, Reducers>
+  }) => {
+    return createSlice({
+      name,
+      initialState,
+      reducers: {
+        start(state) {
+          state.status = 'loading'
+        },
+        success(state: GenericState<T>, action: PayloadAction<T>) {
+          state.data = action.payload
+          state.status = 'finished'
+        },
+        ...reducers
+      }
+    })
+  }
+
+  const wrappedSlice = createGenericSlice({
+    name: 'test',
+    initialState: { status: 'loading' } as GenericState<string>,
+    reducers: {
+      magic(state) {
+        expectType<GenericState<string>>(state)
+        // typings:expect-error
+        expectType<GenericState<number>>(state)
+
+        state.status = 'finished'
+        state.data = 'hocus pocus'
+      }
+    }
+  })
+
+  expectType<ActionCreatorWithPayload<string>>(wrappedSlice.actions.success)
+  expectType<ActionCreatorWithoutPayload<string>>(wrappedSlice.actions.magic)
+}