diff --git a/index.d.ts b/index.d.ts
new file mode 100644
index 0000000000..355dc25ece
--- /dev/null
+++ b/index.d.ts
@@ -0,0 +1,221 @@
+import {
+ Action,
+ ActionCreator,
+ Reducer,
+ AnyAction,
+ Middleware,
+ StoreEnhancer,
+ ReducersMapObject,
+ Store
+} from 'redux'
+
+export {
+ Action,
+ ActionCreator,
+ AnyAction,
+ Middleware,
+ Reducer,
+ ReducersMapObject,
+ Store,
+ StoreEnhancer,
+ combineReducers,
+ compose
+} from 'redux'
+export { default as createSelector } from 'selectorator'
+export { produce as createNextState } from 'immer'
+
+/* configureStore() */
+
+/**
+ * A configuration object that can be passed to `configureStore()`.
+ */
+export interface StoreConfiguration {
+ /**
+ * A single reducer function that will be used as the root reducer, or an
+ * object of slice reducers that will be passed to `combineReducers()`.
+ */
+ reducer: Reducer | ReducersMapObject
+
+ /**
+ * An array of Redux middlewares. If not supplied, defaults to just
+ * `redux-thunk`.
+ */
+ middleware?: Middleware[]
+
+ /**
+ * Whether to enable Redux DevTools integration. Defaults to `true`.
+ */
+ devTools?: boolean
+
+ /**
+ * The initial state. You may optionally specify it to hydrate the state
+ * from the server in universal apps, or to restore a previously serialized
+ * user session. If you use `combineReducers()` to produce the root reducer
+ * function (either directly or indirectly by passing an object as `reducer`),
+ * this must be an object with the same shape as the reducer map keys.
+ */
+ preloadedState?: S
+
+ /**
+ * The store enhancer. See `createStore()`. If you only need to add
+ * middleware, you can use the `middleware` parameter instaead.
+ */
+ enhancer?: StoreEnhancer
+}
+
+/**
+ * A friendlier abstraction over the standard Redux `createStore()` function.
+ *
+ * @param config The store configuration.
+ * @returns A configured Redux store.
+ */
+export function configureStore(
+ config: StoreConfiguration
+): Store
+
+/* getDefaultMiddleware() */
+
+/**
+ * Returns any array containing the default middleware installed by
+ * `configureStore`. Useful if you want to configure your store with a custom
+ * `middleware` array but still keep the default set.
+ */
+export function getDefaultMiddleware(): Middleware[]
+
+/* createAction() */
+
+/**
+ * An action with an associated payload. The type of action returned by
+ * action creators that are generated using {@link createAction}.
+ *
+ * @template P The type of the action's payload.
+ * @template T the type of the action's `type` tag.
+ */
+export interface PayloadAction
extends Action {
+ (): Action
+}
+
+/**
+ * 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
+ */
+export function createAction (
+ type: T
+): PayloadActionCreator
+
+/* createReducer() */
+
+/**
+ * An *action handler* is a reducer for a speficic action type passed to
+ * `createReducer()`. In contrast to a normal Redux reducer, it is never
+ * called with an `undefined` state because the initial state is explicitly
+ * passed as the first argument to `createReducer()`.
+ */
+export interface ActionHandler {
+ (state: S, action: A): S
+}
+
+/**
+ * A mapping from action types to action handlers, meant to be passed to
+ * `createReducer()`.
+ */
+export interface ActionHandlersMapObject {
+ [actionType: string]: ActionHandler
+}
+
+/**
+ * A utility function to create reducers that handle specific action types.
+ * case reducer functions. Internally, it uses the `immer` library, so you
+ * can write code in your case reducers that mutates the existing state value,
+ * and it will correctly generate immutably-updated state values instead.
+ *
+ * @param initialState The initial state to be returned by the reducer.
+ * @param actionsMap A mapping from action types to action handlers
+ * (action-type-specific reducer functions).
+ */
+export function createReducer(
+ initialState: S,
+ actionsMap: ActionHandlersMapObject
+): Reducer
+
+/* createSlice() */
+
+/**
+ * A *slice* bundles a reducer, creators for the actions handled by that
+ * reducer, and selectors for the reducer's state.
+ */
+export interface Slice<
+ S,
+ A extends Action = AnyAction,
+ AT extends string = string
+> {
+ /**
+ * The slice's reducer.
+ */
+ reducer: Reducer
+
+ /**
+ * Action creators for the types of actions that are handled by the slice
+ * reducer.
+ */
+ actions: { [type in AT]: ActionCreator }
+}
+
+/**
+ * A function that accepts an initial state, an object full of reducer
+ * functions, and optionally a "slice name", and automatically generates
+ * action creators, action types, and selectors that correspond to the
+ * reducers and state.
+ *
+ * The reducers are wrapped with `createReducer()`.
+ */
+export function createSlice<
+ S,
+ A extends Action = AnyAction,
+ AT extends string = string
+>(config: SliceConfiguration): Slice
diff --git a/package-lock.json b/package-lock.json
index 80ea00fc97..ef41c38473 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2635,14 +2635,12 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
- "dev": true,
- "optional": true
+ "dev": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
- "optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -2657,20 +2655,17 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
- "dev": true,
- "optional": true
+ "dev": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
- "dev": true,
- "optional": true
+ "dev": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
- "dev": true,
- "optional": true
+ "dev": true
},
"core-util-is": {
"version": "1.0.2",
@@ -2787,8 +2782,7 @@
"inherits": {
"version": "2.0.3",
"bundled": true,
- "dev": true,
- "optional": true
+ "dev": true
},
"ini": {
"version": "1.3.5",
@@ -2800,7 +2794,6 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
- "optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -2815,7 +2808,6 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
- "optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@@ -2823,14 +2815,12 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
- "dev": true,
- "optional": true
+ "dev": true
},
"minipass": {
"version": "2.2.4",
"bundled": true,
"dev": true,
- "optional": true,
"requires": {
"safe-buffer": "^5.1.1",
"yallist": "^3.0.0"
@@ -2849,7 +2839,6 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
- "optional": true,
"requires": {
"minimist": "0.0.8"
}
@@ -2930,8 +2919,7 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
- "dev": true,
- "optional": true
+ "dev": true
},
"object-assign": {
"version": "4.1.1",
@@ -2943,7 +2931,6 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
- "optional": true,
"requires": {
"wrappy": "1"
}
@@ -3065,7 +3052,6 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
- "optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@@ -7127,6 +7113,21 @@
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
"dev": true
},
+ "typescript": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.2.tgz",
+ "integrity": "sha512-VCj5UiSyHBjwfYacmDuc/NOk4QQixbE+Wn7MFJuS0nRuPQbof132Pw4u53dm264O8LPc2MVsc7RJNml5szurkg==",
+ "dev": true
+ },
+ "typings-tester": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/typings-tester/-/typings-tester-0.3.2.tgz",
+ "integrity": "sha512-HjGoAM2UoGhmSKKy23TYEKkxlphdJFdix5VvqWFLzH1BJVnnwG38tpC6SXPgqhfFGfHY77RlN1K8ts0dbWBQ7A==",
+ "dev": true,
+ "requires": {
+ "commander": "^2.12.2"
+ }
+ },
"uglify-js": {
"version": "3.4.9",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz",
diff --git a/package.json b/package.json
index 61ec2e8b08..c72952726f 100644
--- a/package.json
+++ b/package.json
@@ -25,7 +25,9 @@
"rollup-plugin-babel": "^3.0.3",
"rollup-plugin-commonjs": "^8.3.0",
"rollup-plugin-node-resolve": "^3.0.3",
- "rollup-plugin-replace": "^2.1.0"
+ "rollup-plugin-replace": "^2.1.0",
+ "typescript": "^3.2.2",
+ "typings-tester": "^0.3.2"
},
"scripts": {
"build": "rollup -c",
@@ -37,7 +39,8 @@
"test": "jest"
},
"files": [
- "dist"
+ "dist",
+ "index.d.ts"
],
"dependencies": {
"immer": "^1.9.3",
diff --git a/typing-tests/typescript.test.js b/typing-tests/typescript.test.js
new file mode 100644
index 0000000000..632b51cd3a
--- /dev/null
+++ b/typing-tests/typescript.test.js
@@ -0,0 +1,5 @@
+import { checkDirectory } from 'typings-tester'
+
+test('TypeScript definitions', () => {
+ checkDirectory(`${__dirname}/typescript`)
+})
diff --git a/typing-tests/typescript/configureStore.ts b/typing-tests/typescript/configureStore.ts
new file mode 100644
index 0000000000..df2f1cf36e
--- /dev/null
+++ b/typing-tests/typescript/configureStore.ts
@@ -0,0 +1,124 @@
+import { applyMiddleware } from 'redux'
+import {
+ AnyAction,
+ configureStore,
+ Middleware,
+ PayloadAction,
+ Reducer,
+ Store
+} from 'redux-starter-kit'
+
+/*
+ * Test: configureStore() requires a valid reducer or reducer map.
+ */
+{
+ configureStore({
+ reducer: (state, action) => 0
+ })
+
+ configureStore({
+ reducer: {
+ counter1: () => 0,
+ counter2: () => 1
+ }
+ })
+
+ // typings:expect-error
+ configureStore({ reducer: 'not a reducer' })
+
+ // typings:expect-error
+ configureStore({ reducer: { a: 'not a reducer' } })
+
+ // typings:expect-error
+ configureStore({})
+}
+
+/*
+ * Test: configureStore() infers the store state type.
+ */
+{
+ const reducer: Reducer