# Redux Administrator & Developer Guide

## 1. Architecture Overview

Redux is a predictable state container for JavaScript applications. At its core, it implements a minimal, framework-agnostic state machine: a single store holds an immutable state tree, plain-object actions describe state transitions, and pure reducer functions compute the next state. The entire public API surface consists of seven functions and two utilities, totaling under 700 lines of TypeScript source.

Redux is not an application framework — it is a coordination primitive. Its value comes from the strict constraints it enforces (immutability, unidirectional data flow, pure reducers) and the ecosystem those constraints enable (time-travel debugging, middleware pipelines, hot reloading, server-side rendering).

The Redux team now recommends **Redux Toolkit** (`@reduxjs/toolkit`) as the standard way to write Redux logic. Redux Toolkit wraps this core package with `configureStore`, `createSlice`, `createAsyncThunk`, and other utilities. This guide documents the core `redux` package internals that Redux Toolkit builds upon.

### Architecture Diagram

```text
                        ┌──────────────────────┐
                        │     Application       │
                        │                       │
                        │  dispatch(action) ────┤
                        │                       │
                        │  ◄── subscribe() ─────┤
                        │  ◄── getState() ──────┤
                        └───────────┬───────────┘
                                    │
                        ┌───────────▼───────────┐
                        │        Store          │
                        │                       │
                        │  ┌─────────────────┐  │
                        │  │   Middleware     │  │
                        │  │   Chain          │  │
                        │  │  (applyMiddle-   │  │
                        │  │   ware)          │  │
                        │  └────────┬────────┘  │
                        │           │           │
                        │  ┌────────▼────────┐  │
                        │  │  Root Reducer   │  │
                        │  │  (combine-      │  │
                        │  │   Reducers)     │  │
                        │  └────────┬────────┘  │
                        │           │           │
                        │  ┌────────▼────────┐  │
                        │  │  State Tree     │  │
                        │  │  (immutable)    │  │
                        │  └─────────────────┘  │
                        │                       │
                        │  Listeners (Map)      │
                        └───────────────────────┘
```

### Component Inventory

| Component | Source Path | Role |
|---|---|---|
| `createStore` | `src/createStore.ts` | Store factory — holds state, manages dispatch/subscribe/getState lifecycle |
| `combineReducers` | `src/combineReducers.ts` | Merges multiple slice reducers into a single root reducer |
| `applyMiddleware` | `src/applyMiddleware.ts` | Store enhancer that composes a middleware chain around `dispatch` |
| `bindActionCreators` | `src/bindActionCreators.ts` | Wraps action creators with `dispatch` for direct invocation |
| `compose` | `src/compose.ts` | Right-to-left function composition utility |
| `isAction` | `src/utils/isAction.ts` | Type guard — checks plain object with string `type` |
| `isPlainObject` | `src/utils/isPlainObject.ts` | Prototype-chain check for plain objects |
| `actionTypes` | `src/utils/actionTypes.ts` | Internal action types (`@@redux/INIT`, `REPLACE`, `PROBE_UNKNOWN_ACTION`) |
| `warning` | `src/utils/warning.ts` | Development-only `console.error` with breakpoint trick |
| `kindOf` | `src/utils/kindOf.ts` | Human-readable type name for error messages (dev only) |
| `formatProdErrorMessage` | `src/utils/formatProdErrorMessage.ts` | Minified error codes with URL links for production |
| `symbol-observable` | `src/utils/symbol-observable.ts` | TC39 `Symbol.observable` polyfill |

### Technology Stack

| Layer | Technology |
|---|---|
| Language | TypeScript 5.x (strict mode, `exactOptionalPropertyTypes`) |
| Build | tsup (esbuild-based, 4 output formats) |
| Test | Vitest (runtime + type-level tests via `--typecheck`) |
| Lint | ESLint with `@typescript-eslint` |
| Format | Prettier (no semicolons, single quotes, trailing comma: none) |
| Package Manager | Yarn 4.4.1 (PnP disabled, `nodeLinker: node-modules`) |
| CI/CD | Netlify (website), npm publish |
| Documentation Site | Docusaurus 3.6.3 (in `website/`) |

### Data Flow

1. Application calls `store.dispatch(action)` with a plain object
2. If middleware is applied, the action passes through the middleware chain (each middleware can inspect, modify, delay, or replace the action)
3. The innermost middleware calls the original `store.dispatch`, which:
   - Validates the action is a plain object with a string `type`
   - Calls `currentReducer(currentState, action)` synchronously
   - Replaces `currentState` with the return value
   - Iterates all registered listeners (Map-based, snapshot before dispatch)
4. The dispatched action object is returned to the caller

> [!NOTE]
> The listener collection uses a `Map<number, ListenerCallback>` with numeric IDs, not an array. Subscriptions and unsubscriptions during a dispatch take effect on the *next* dispatch, not the current one — the listener list is snapshotted via shallow copy before iteration.

## 2. System Requirements

### Runtime Requirements

| Requirement | Detail |
|---|---|
| JavaScript Engine | Any ES2015+ environment (all modern browsers, Node.js 14+) |
| Required Globals | `Map`, `Object.getPrototypeOf`, `Symbol` (for observable interop) |
| Dependencies | **None** — zero runtime dependencies |

### Development Requirements

| Requirement | Version |
|---|---|
| Node.js | 14+ (20 for website build) |
| Yarn | 4.4.1 (ships via `.yarnrc.yml` → `.yarn/releases/yarn-4.4.1.cjs`) |
| TypeScript | 5.8.2+ |

### Build Output Sizes

The library is extremely small. The `sideEffects: false` flag enables complete tree-shaking for ESM consumers.

## 3. Configuration Reference

Redux has no configuration files. All configuration is code-level, passed to `createStore` at instantiation.

### `createStore` Parameters

| Parameter | Type | Required | Description |
|---|---|---|---|
| `reducer` | `Reducer<S, A>` | Yes | Root reducer function: `(state, action) => newState` |
| `preloadedState` | `S` | No | Initial state for hydration (SSR) or restored sessions |
| `enhancer` | `StoreEnhancer` | No | Store enhancer (e.g., `applyMiddleware(...)`, composed enhancers) |

> [!IMPORTANT]
> If `preloadedState` is omitted and the second argument is a function, Redux treats it as the `enhancer`. This enables the two-argument form: `createStore(reducer, enhancer)`.

### `combineReducers` Behavior

| Aspect | Detail |
|---|---|
| Input | Object mapping keys to reducer functions |
| Validation | Calls each reducer with `undefined` state + `@@redux/INIT` action; throws if any returns `undefined` |
| Probing | Calls each reducer with `undefined` state + random action type; throws if any returns `undefined` |
| Unknown keys | In development, logs a warning if state contains keys with no matching reducer |
| Reference equality | Returns the same state object if no slice reducer returns a new value |

### `applyMiddleware` Behavior

| Aspect | Detail |
|---|---|
| Input | Variadic list of middleware functions |
| Middleware API | Each middleware receives `{ getState, dispatch }` — note: `dispatch` is the *enhanced* dispatch, not the original |
| Chain construction | `compose(...middlewares.map(m => m(middlewareAPI)))(store.dispatch)` |
| Return | A `StoreEnhancer` that wraps `createStore` |

### Environment Variables

| Variable | Scope | Effect |
|---|---|---|
| `NODE_ENV` | Build-time | `production`: strips dev warnings, uses `formatProdErrorMessage` with numeric codes. `development`: enables `kindOf()` detailed type names, `combineReducers` shape warnings, `console.error` warnings. |

### Build Configuration

The build is configured via `tsup.config.ts`:

| Output | Format | Minified | `NODE_ENV` | File |
|---|---|---|---|---|
| Standard ESM | `esm` | No | Embedded checks | `dist/redux.mjs` |
| Legacy ESM | `esm` (ES2017 target) | No | Embedded checks | `dist/redux.legacy-esm.js` |
| Browser ESM | `esm` | Yes | `production` (hardcoded) | `dist/redux.browser.mjs` |
| CJS | `cjs` | No | Embedded checks | `dist/cjs/redux.cjs` |
| Type Declarations | — | — | — | `dist/redux.d.mts` |

All builds use sourcemaps. The `mangleErrorsTransform` Babel plugin replaces verbose error strings with numeric codes (mapped in `errors.json`) for production builds.

### TypeScript Configuration

Three `tsconfig` files serve different purposes:

| Config | Extends | Purpose |
|---|---|---|
| `tsconfig.base.json` | — | Shared settings: `strict`, `exactOptionalPropertyTypes`, `isolatedModules`, path aliases (`@internal/*` → `./src/*`, `redux` → `./src/index.ts`) |
| `tsconfig.build.json` | `base` | Library build: `emitDeclarationOnly`, outputs to `dist/` |
| `tsconfig.test.json` | `base` | Type-level tests: `noEmit`, includes `test/typescript/` |

> [!NOTE]
> The `redux` path alias in `tsconfig.base.json` is annotated `// @remap-prod-remove-line` — it is stripped during production builds so tests can import from the source directly while published types point to the built output.

## 4. Deployment & Scaling

### Publishing

The package is published to npm as `redux`. The publish lifecycle:

1. `prepublishOnly`: clean → format check → lint → test
2. `prepack`: clean → tsup build (4 output formats + types)
3. npm publish uploads `dist/` and `src/` (per `"files"` in `package.json`)

### Release Management

Releases use `release-it` (configured in `.release-it.json`):

```json
{
  "hooks": {
    "after:bump": "yarn && git add -u"
  },
  "git": {
    "tagName": "v${version}"
  }
}
```

Git tags follow the `v{version}` format (e.g., `v5.0.1`).

### Website Deployment

The documentation website deploys to Netlify:

- **Build base:** `website/`
- **Build command:** `cd ../docs && yarn && cd ../website && yarn build && cp _redirects ./build`
- **Publish directory:** `website/build`
- **Skip condition:** `git diff --quiet HEAD^ HEAD -- ../docs/ .` (only rebuilds if docs or website changed)
- **Node version:** 20
- **Caching:** `node_modules/.cache`, `website/node_modules/.cache`, `.yarn/.cache`

### Bundle Size Considerations

Redux is designed to be as small as possible:

- Zero runtime dependencies
- `sideEffects: false` enables tree-shaking
- Production builds use minified error codes (see `errors.json`)
- The `compose` function inlines — if only `createStore` is imported, `compose`, `bindActionCreators`, etc. are tree-shaken away

> [!TIP]
> The browser-ready ESM build (`dist/redux.browser.mjs`) is pre-minified with `NODE_ENV=production` hardcoded. Use it for direct `<script type="module">` inclusion without a build step.

## 5. Operations

### Development Workflow

```bash
# Install dependencies
yarn

# Run tests (runtime + type-level)
yarn test

# Run tests in watch mode
yarn test:watch

# Run tests with coverage
yarn test:cov

# Type-check the type-level tests only
yarn type-tests

# Lint
yarn lint

# Format
yarn format

# Build all outputs
yarn build

# Lint examples
yarn examples:lint
```

### Error Code System

Redux uses a Babel plugin (`scripts/mangleErrors.mts`) that replaces verbose error strings with numeric codes in production builds. The mapping lives in `errors.json`:

| Code | Error |
|---|---|
| 0 | Passing several store enhancers to createStore() |
| 1 | Expected enhancer to be a function |
| 2 | Expected root reducer to be a function |
| 3 | Cannot call getState() while reducer is executing |
| 4 | Expected listener to be a function |
| 5 | Cannot call subscribe() while reducer is executing |
| 6 | Cannot unsubscribe while reducer is executing |
| 7 | Actions must be plain objects |
| 8 | Actions may not have undefined type |
| 9 | Reducers may not dispatch actions |
| 10 | Expected nextReducer to be a function |
| 11 | Expected observer to be an object |
| 12 | Slice reducer returned undefined during initialization |
| 13 | Slice reducer returned undefined when probed |
| 14 | Slice reducer returned undefined for action |
| 15 | Dispatching while constructing middleware |
| 16 | bindActionCreators expected object or function |
| 17 | Action type must be a string |

In production, users see: `Minified Redux error #7; visit https://redux.js.org/Errors?code=7 for the full message`

> [!NOTE]
> The error code system mirrors React's approach. The `errors.json` file is the source of truth for the mapping between codes and full messages.

### Monitoring and Debugging

Redux is designed for observability through Redux DevTools:

- **Time-travel debugging:** replay actions, jump to any previous state
- **Action inspection:** view every dispatched action and its payload
- **State diff:** see what changed between dispatches
- **Import/export:** save and load state snapshots

Integration via the DevTools Extension Compose:

```javascript
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
const store = createStore(reducer, composeEnhancers(applyMiddleware(thunk)))
```

> [!TIP]
> Redux Toolkit's `configureStore` enables DevTools automatically in development. With the core `redux` package, you must compose the DevTools enhancer manually.

## 6. Performance

### State Reference Equality

`combineReducers` returns the same state object reference if no slice reducer returns a new value. This enables efficient change detection in UI libraries:

```javascript
// Inside combineReducers:
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
// ...
hasChanged = hasChanged || finalReducerKeys.length !== Object.keys(state).length
return hasChanged ? nextState : state
```

### Listener Implementation

Listeners use a `Map<number, ListenerCallback>` with numeric IDs (auto-incrementing counter). This is more efficient than array-based implementations for frequent subscribe/unsubscribe patterns. The listener map is copy-on-write: `ensureCanMutateNextListeners()` creates a shallow copy only when needed.

### Middleware Chain

The middleware chain is composed once at store creation via `compose`. Each dispatch passes through the chain with zero additional allocation — middleware functions are pre-composed into a single function reference.

## 7. Security

### Action Validation

Redux enforces strict action validation in the `dispatch` function:

1. **Plain object check:** `isPlainObject(action)` — rejects class instances, arrays, Promises, functions
2. **Type existence check:** `typeof action.type === 'undefined'` → error
3. **Type string check:** `typeof action.type !== 'string'` → error (new in Redux 5.x)
4. **Re-entrancy guard:** `isDispatching` flag prevents dispatch during reducer execution

### Serialization Safety

For SSR, Redux state must be serialized to HTML. The recommended pattern escapes `<` to prevent XSS:

```javascript
JSON.stringify(preloadedState).replace(/</g, '\\x3c')
```

> [!CAUTION]
> Failing to escape serialized state enables XSS attacks via crafted state values containing `</script>` tags. Always sanitize when embedding state in HTML.

### Supply Chain

- Zero runtime dependencies (the library depends on nothing at runtime)
- All devDependencies are well-known packages from the JS ecosystem
- The `sideEffects: false` declaration ensures no code runs on import alone

### Observable Protocol

The `Symbol.observable` interop uses a defensive check:

```typescript
const $$observable = (() =>
  (typeof Symbol === 'function' && Symbol.observable) || '@@observable')()
```

This falls back to a string key if `Symbol.observable` is not available, maintaining compatibility without polyfill requirements.

## 8. Developer Internals

### Repository Structure

```text
redux/
├── src/                    # Core library source (TypeScript)
│   ├── index.ts            # Public API barrel export
│   ├── createStore.ts      # Store factory (createStore, legacy_createStore)
│   ├── combineReducers.ts  # Reducer composition
│   ├── applyMiddleware.ts  # Middleware store enhancer
│   ├── bindActionCreators.ts # Action creator dispatch binding
│   ├── compose.ts          # Right-to-left function composition
│   ├── types/              # TypeScript type definitions
│   │   ├── actions.ts      # Action, UnknownAction, AnyAction, ActionCreator
│   │   ├── middleware.ts   # Middleware, MiddlewareAPI
│   │   ├── reducers.ts     # Reducer, ReducersMapObject, derived types
│   │   └── store.ts        # Store, Dispatch, StoreEnhancer, Observable
│   └── utils/              # Internal utilities
│       ├── actionTypes.ts  # @@redux/INIT, REPLACE, PROBE_UNKNOWN_ACTION
│       ├── formatProdErrorMessage.ts  # Minified error codes
│       ├── isAction.ts     # Action type guard
│       ├── isPlainObject.ts # Plain object check
│       ├── kindOf.ts       # Dev-mode type name utility
│       ├── symbol-observable.ts # Symbol.observable polyfill
│       └── warning.ts      # Dev-mode console.error wrapper
├── test/                   # Test suite
│   ├── *.spec.ts           # Runtime tests (one per core module)
│   ├── helpers/            # Test utilities (mock reducers, actions, middleware)
│   ├── utils/              # Tests for utility functions
│   └── typescript/         # Type-level tests (*.test-d.ts)
├── examples/               # 10 example applications
│   ├── async/              # Async data fetching with redux-thunk
│   ├── counter/            # React + RTK counter (JS)
│   ├── counter-ts/         # React + RTK counter (TypeScript)
│   ├── counter-vanilla/    # Vanilla JS counter (no React)
│   ├── real-world/         # GitHub API browser with pagination
│   ├── shopping-cart/      # Shopping cart with optimistic updates
│   ├── todomvc/            # TodoMVC with reselect
│   ├── todos/              # Basic todo list
│   ├── todos-with-undo/    # Todos with redux-undo
│   ├── tree-view/          # Dynamic tree with normalized state
│   └── universal/          # Server-side rendering (Express + React)
├── website/                # Docusaurus documentation site
├── docs/                   # Markdown documentation source
├── scripts/                # Build scripts
│   └── mangleErrors.mts    # Babel plugin for error code extraction
├── errors.json             # Error code → message mapping
├── tsup.config.ts          # Build configuration (4 output formats)
├── tsconfig.base.json      # Shared TypeScript settings
├── tsconfig.build.json     # Build-specific TypeScript config
├── tsconfig.test.json      # Type-test TypeScript config
├── vitest.config.mts       # Test runner configuration
├── package.json            # Package metadata (v5.0.1)
└── netlify.toml            # Website deployment config
```

### Module Reference

#### `createStore.ts` — Store Factory

The central module. Creates the store object with `getState`, `dispatch`, `subscribe`, `replaceReducer`, and `[Symbol.observable]` methods.

**Internal state:**

| Variable | Type | Purpose |
|---|---|---|
| `currentReducer` | `Reducer` | The active root reducer |
| `currentState` | `S \| PreloadedState \| undefined` | The current state tree |
| `currentListeners` | `Map<number, ListenerCallback> \| null` | Active listener map (set to `null` after unsubscribe to allow GC) |
| `nextListeners` | `Map<number, ListenerCallback>` | Next listener map (copy-on-write) |
| `listenerIdCounter` | `number` | Auto-incrementing listener ID |
| `isDispatching` | `boolean` | Re-entrancy guard |

**Key behaviors:**

- On creation, dispatches `{ type: '@@redux/INIT{random}' }` to populate initial state
- `replaceReducer` dispatches `{ type: '@@redux/REPLACE{random}' }` to re-initialize
- Random suffixes on internal action types prevent reducers from matching them
- `dispatch` returns the dispatched action object (middleware may return something else)
- `subscribe` returns an `unsubscribe` function; calling it twice is a no-op
- The `@@observable` method returns a minimal observable that calls `observer.next(getState())` on every state change

**`createStore` vs `legacy_createStore`:** Both are exported. `createStore` carries a `@deprecated` JSDoc annotation; `legacy_createStore` is identical in behavior but without the deprecation marker. `legacy_createStore` delegates to `createStore` internally.

#### `combineReducers.ts` — Reducer Composition

Merges an object of slice reducers into a single root reducer.

**Validation (at construction time):**

1. Filters out non-function values from the input object
2. Warns (dev only) if any key maps to `undefined`
3. Calls `assertReducerShape` — invokes each reducer with:
   - `undefined` state + `@@redux/INIT` action → must not return `undefined`
   - `undefined` state + `@@redux/PROBE_UNKNOWN_ACTION{random}` → must not return `undefined`

**Runtime (on each dispatch):**

1. Iterates `finalReducerKeys`, calls each slice reducer with its slice of state + action
2. Checks if any slice returned a new value (reference inequality)
3. Also checks if the number of state keys changed
4. Returns new state object only if something changed; otherwise returns the same reference

**Dev-mode warnings:**

- Unexpected keys in state that don't match any reducer
- Unexpected state shape (not a plain object)

#### `applyMiddleware.ts` — Middleware Enhancer

Returns a `StoreEnhancer` that intercepts `createStore` to wrap `dispatch`.

**Composition:**

```typescript
const middlewareAPI: MiddlewareAPI = {
  getState: store.getState,
  dispatch: (action, ...args) => dispatch(action, ...args)
}
const chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose<typeof dispatch>(...chain)(store.dispatch)
```

The `dispatch` reference in `middlewareAPI` is a closure — it always points to the latest composed dispatch, not the original. This allows middleware to dispatch through the full chain.

> [!WARNING]
> Calling `dispatch` during middleware construction (before the chain is composed) throws: "Dispatching while constructing your middleware is not allowed." The initial `dispatch` is a throwing stub that gets replaced once composition completes.

#### `bindActionCreators.ts` — Dispatch Binding

Accepts a single action creator or an object of action creators and a `dispatch` function. Returns wrapped versions that call `dispatch(actionCreator(...args))` automatically.

**Edge cases:**

- Non-function values in the input object are silently skipped
- Passing neither a function nor an object throws with a descriptive error including `kindOf()` type name
- The bound function preserves `this` context via `.apply(this, args)`

#### `compose.ts` — Function Composition

Composes functions from right to left. Special cases:

| Input | Output |
|---|---|
| 0 functions | Identity function: `(arg) => arg` |
| 1 function | Returns that function directly |
| N functions | `funcs.reduce((a, b) => (...args) => a(b(...args)))` |

Heavily overloaded in TypeScript (up to 4 functions with full type inference, then rest-args fallback).

#### `src/utils/` — Internal Utilities

| Module | Description |
|---|---|
| `actionTypes.ts` | Three internal action types with random suffixes: `INIT` (fired on store creation), `REPLACE` (fired on `replaceReducer`), `PROBE_UNKNOWN_ACTION` (used by `assertReducerShape` to verify reducers handle unknown actions) |
| `isPlainObject.ts` | Walks the prototype chain to check if an object's prototype is `Object.prototype` or `null`. Rejects class instances, arrays, Dates, etc. |
| `isAction.ts` | Combines `isPlainObject` with a check for `'type' in action` and `typeof type === 'string'` |
| `kindOf.ts` | In development, returns a human-readable type name (e.g., `'array'`, `'date'`, `'promise'`, `'weakmap'`). In production, returns raw `typeof`. Used only for error messages. |
| `warning.ts` | Calls `console.error(message)`, then `throw new Error(message)` inside a try/catch. The throw enables "break on all exceptions" in browser DevTools without actually propagating. |
| `formatProdErrorMessage.ts` | Returns a message directing users to `redux.js.org/Errors?code=N`. Used by the `mangleErrors` Babel plugin to replace verbose error strings in production builds. |
| `symbol-observable.ts` | Returns `Symbol.observable` if available, otherwise the string `'@@observable'`. Used as a method key on the store for observable interop. |

### Type System Architecture

Redux 5.0.1 exports a comprehensive type system from `src/types/`:

#### `types/actions.ts`

| Type | Description |
|---|---|
| `Action<T = string>` | `{ type: T }` — base action interface |
| `UnknownAction` | `{ type: string; [extraProps: string]: unknown }` — replaces `AnyAction` |
| `AnyAction` | Legacy alias for `UnknownAction` (deprecated) |
| `ActionCreator<A>` | `(...args: any[]) => A` |
| `ActionCreatorsMapObject<A>` | `{ [key: string]: ActionCreator<A> }` |

#### `types/store.ts`

| Type | Description |
|---|---|
| `Store<S, A, StateExt>` | The store interface with `getState`, `dispatch`, `subscribe`, `replaceReducer`, `[Symbol.observable]` |
| `Dispatch<A>` | `(action: A) => A` |
| `Unsubscribe` | `() => void` |
| `StoreEnhancer<Ext, StateExt>` | `(createStore) => (reducer, preloadedState) => Store` |
| `StoreCreator` | The `createStore` function type |
| `StoreEnhancerStoreCreator` | Return type of `StoreEnhancer` |
| `Observable<T>` / `Observer<T>` | TC39 Observable interop types |
| `ListenerCallback` | `() => void` |
| `UnknownIfNonSpecific<T>` | Utility type: resolves to `unknown` if `T` is `{}` |

#### `types/reducers.ts`

| Type | Description |
|---|---|
| `Reducer<S, A, PreloadedState>` | `(state: S \| PreloadedState \| undefined, action: A) => S` |
| `ReducersMapObject<S, A>` | `{ [K in keyof S]: Reducer<S[K], A> }` |
| `StateFromReducersMapObject<M>` | Derives the combined state type from a reducers map |
| `ActionFromReducersMapObject<M>` | Union of all action types accepted by reducers in the map |
| `PreloadedStateShapeFromReducersMapObject<M>` | `Partial<>` of the derived state (for preloaded state) |

#### `types/middleware.ts`

| Type | Description |
|---|---|
| `MiddlewareAPI<D, S>` | `{ dispatch: D; getState: () => S }` |
| `Middleware<Ext, S, D>` | `(api: MiddlewareAPI) => (next: D) => (action: any) => any` |

### Code Patterns and Conventions

**Formatting (from `.prettierrc.json`):**

| Setting | Value |
|---|---|
| Semicolons | `false` |
| Quotes | Single |
| Tab width | 2 |
| Trailing commas | None |
| Arrow parens | Avoid |

**Error handling pattern:** All public functions validate inputs and throw `Error` with descriptive messages (dev) or coded messages (prod). The `kindOf()` utility provides type names in error strings.

**Copy-on-write listeners:** The listener `Map` is shallow-copied before mutation via `ensureCanMutateNextListeners()`. This prevents bugs when subscribers add/remove listeners during notification.

**Internal action types use random suffixes:**

```typescript
INIT: `@@redux/INIT${randomString()}`
REPLACE: `@@redux/REPLACE${randomString()}`
PROBE_UNKNOWN_ACTION: () => `@@redux/PROBE_UNKNOWN_ACTION${randomString()}`
```

This ensures no reducer accidentally handles these internal actions. `PROBE_UNKNOWN_ACTION` is a function (not a string) because it must generate a unique value on each call during `assertReducerShape`.

### Testing Strategy

**Runtime tests** (`test/*.spec.ts`):

| Test File | Coverage |
|---|---|
| `createStore.spec.ts` | Store creation, dispatch, subscribe, getState, replaceReducer, observable, error paths |
| `combineReducers.spec.ts` | Reducer combination, shape validation, warning behavior |
| `applyMiddleware.spec.ts` | Middleware chain composition, dispatch wrapping |
| `bindActionCreators.spec.ts` | Single and map binding, error cases |
| `compose.spec.ts` | 0-arg, 1-arg, multi-arg composition |

**Utility tests** (`test/utils/*.spec.ts`):

| Test File | Coverage |
|---|---|
| `isAction.spec.ts` | Plain object + string type validation |
| `isPlainObject.spec.ts` | Prototype chain checks |
| `warning.spec.ts` | Console.error behavior |
| `formatProdErrorMessage.spec.ts` | Error code formatting |

**Type-level tests** (`test/typescript/*.test-d.ts`):

9 type-test files using Vitest's `expectTypeOf` assertions:

| Test File | Coverage |
|---|---|
| `store.test-d.ts` | Store type inference, enhancer composition |
| `dispatch.test-d.ts` | Dispatch type narrowing |
| `reducers.test-d.ts` | Reducer type derivation |
| `middleware.test-d.ts` | Middleware type chain |
| `compose.test-d.ts` | Compose overload resolution |
| `enhancers.test-d.ts` | Store enhancer type composition |
| `actions.test-d.ts` | Action type constraints |
| `actionCreators.test-d.ts` | Action creator type inference |
| `injectedDispatch.test-d.ts` | Enhanced dispatch types from middleware |

**Test helpers** (`test/helpers/`):

| File | Contents |
|---|---|
| `actionCreators.ts` | `addTodo`, `addTodoAsync`, `addTodoIfEmpty`, `unknownAction`, `dispatchInMiddle`, `getStateInMiddle`, `subscribeInMiddle`, `unsubscribeInMiddle`, `throwError`, `noop` |
| `actionTypes.ts` | `ADD_TODO`, `DISPATCH_IN_MIDDLE`, `GET_STATE_IN_MIDDLE`, `SUBSCRIBE_IN_MIDDLE`, `UNSUBSCRIBE_IN_MIDDLE`, `THROW_ERROR`, `UNKNOWN_ACTION` |
| `middleware.ts` | `thunk` (minimal thunk middleware for tests) |
| `reducers.ts` | `reducerNoop`, `reducerA`–`reducerC` (with state shapes), combined reducers |

**Running tests:**

```bash
yarn test            # Full suite (runtime + typecheck)
yarn test:watch      # Watch mode
yarn test:cov        # With coverage
yarn type-tests      # Type-level tests only (tsc --noEmit)
```

### Example Applications

The `examples/` directory contains 10 example apps demonstrating different Redux patterns:

| Example | Stack | Pattern Demonstrated |
|---|---|---|
| `counter` | React + RTK | Basic `configureStore` + `createSlice` (JS) |
| `counter-ts` | React + RTK | Same as counter, in TypeScript |
| `counter-vanilla` | Vanilla JS | Redux without any framework; raw DOM manipulation |
| `todos` | React + Redux | Basic todo list with `combineReducers` |
| `todos-with-undo` | React + Redux + redux-undo | Undo/redo history |
| `todomvc` | React + Redux + reselect | Full TodoMVC spec with memoized selectors |
| `async` | React + Redux + redux-thunk | Async data fetching from Reddit API |
| `shopping-cart` | React + Redux + redux-thunk | Shopping cart with mock API and optimistic updates |
| `real-world` | React + Redux + custom middleware | GitHub API with pagination, caching, normalization (normalizr) |
| `tree-view` | React + Redux | Dynamic tree with normalized flat state |
| `universal` | Express + React + Redux | Server-side rendering with state hydration |

> [!NOTE]
> The `counter` and `counter-ts` examples use Redux Toolkit (`@reduxjs/toolkit`), not the core `redux` package directly. All other examples use core Redux APIs (`createStore`, `combineReducers`, `applyMiddleware`).

### Potential Improvements

Based on source analysis and community issues:

1. **Documentation consolidation** — GitHub issue #4789 discusses merging Redux, RTK, and React-Redux docs into a unified site
2. **Outdated tutorial content** — Issue #4480 notes tutorials use legacy `ReactDOM.render()` instead of `createRoot()`. Issue #4375 reports broken reactions in the Essentials tutorial
3. **Reselect docs drift** — Issue #4866 flags outdated Reselect references in the selectors guide
4. **Next.js guidance** — Issue #4713 requests per-route state documentation for Next.js
5. **Type improvements** — Issue #3455 reports `ActionCreator` generic losing argument types; issue #4602 reports conflicts between `AppThunk` and `createAsyncThunk.withTypes`
6. **Normalizr replacement** — Issue #4699 notes normalizr is no longer maintained; the docs still reference it

### Contributing

**Code style:**

```bash
yarn format         # Auto-format with Prettier
yarn format:check   # Check formatting without modifying
yarn lint           # ESLint
```

**Pre-publish checks:** `prepublishOnly` runs format check, lint, and full test suite.

**Git conventions:**

- Tags: `v{version}` (e.g., `v5.0.1`)
- `.git-blame-ignore-revs` exists for large formatting commits
- `.editorconfig` and `.prettierrc.json` enforce consistent formatting

**License:** MIT

## 9. Integration Points

### Observable Protocol

Redux stores implement the TC39 Observable proposal via `Symbol.observable` (or the `@@observable` string fallback). This enables interop with:

- RxJS: `from(store).pipe(...)`
- most.js: `from(store).map(...)`
- Any library implementing the Observable consumer protocol

The observable emits the full state tree on every dispatch via `observer.next(getState())`.

### Store Enhancer Protocol

Store enhancers wrap `createStore` to add capabilities. The enhancer signature:

```typescript
type StoreEnhancer = (createStore: StoreCreator) =>
  (reducer: Reducer, preloadedState?: any) => Store
```

Examples: `applyMiddleware`, Redux DevTools Extension, persistence enhancers. Enhancers compose via `compose`:

```javascript
const enhancer = compose(
  applyMiddleware(thunk, logger),
  devToolsEnhancer,
  persistEnhancer
)
```

### Middleware Protocol

Middleware functions follow a curried three-layer pattern:

```typescript
type Middleware = (api: { dispatch, getState }) =>
  (next: Dispatch) =>
  (action: Action) => any
```

- **Outer function:** receives `{ dispatch, getState }` — called once at store creation
- **Middle function:** receives `next` — the next middleware's dispatch (or the store's base dispatch for the last middleware)
- **Inner function:** receives `action` — called on every dispatch

### React Integration

Via `react-redux`, Redux integrates with React through:

- `<Provider store={store}>` — context-based store injection
- `useSelector(selector)` — subscribe to state slices with reference equality
- `useDispatch()` — access the store's dispatch function
- `connect(mapState, mapDispatch)` — HOC-based integration (legacy pattern)

---

_Generated May 2026 from reduxjs/redux at 0d8fae6. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
