# What Are the Constraints on Action Type Values in Redux?

> Learn the constraints for action type values in Redux. Discover why action types must be strings and actions plain objects to avoid dispatch errors and ensure predictable state management.

- Repository: [Redux/redux](https://github.com/reduxjs/redux)
- Tags: internals
- Published: 2026-03-05

---

**In Redux, the `type` field of an action must be a string, the action itself must be a plain object, and `store.dispatch()` will throw an error if either constraint is violated.**

The `reduxjs/redux` repository enforces strict constraints on action type values to ensure predictable state management and debugging capabilities. These constraints on action type values in Redux are validated at runtime within the store's dispatch mechanism and reinforced through TypeScript type definitions.

## The Core Constraint: String-Only Action Types

According to the Redux migration documentation at [`docs/usage/migrations/migrating-rtk-2.md`](https://github.com/reduxjs/redux/blob/main/docs/usage/migrations/migrating-rtk-2.md), action types must be strings. This is the only required property of a Redux action, and it cannot be omitted or replaced with other data types.

The store rejects any action where:

- The `type` property is missing entirely
- The `type` value is not a string (e.g., a `Symbol`, function, or object)
- The action itself is not a plain object (e.g., a function or class instance)

## Runtime Enforcement in store.dispatch

The validation logic resides in [`src/createStore.ts`](https://github.com/reduxjs/redux/blob/main/src/createStore.ts), where the `dispatch` method checks the action before processing it. If `action.type` is not a string, the store throws a descriptive error immediately.

This runtime check serves as the primary defense against non-serializable actions entering the Redux store. The enforcement ensures that every action flowing through the system can be logged, serialized, and replayed by middleware and development tools.

## Why Redux Enforces These Rules

The rationale behind restricting action type values to strings spans three key architectural concerns:

### Serializability and DevTools

Strings can be serialized and logged, which keeps the Redux DevTools history readable and enables time-travel debugging. Non-string types like `Symbol` or function references cannot be serialized across processes or stored in plain JSON, breaking debugging capabilities.

### Predictability in Reducers

A plain-object action with a string `type` ensures reducers can reliably switch on that value using standard control flow statements. String comparison is deterministic and works across all JavaScript environments, unlike object or function identity checks.

### Flux Standard Action Compatibility

The constraint aligns with the Flux Standard Action (FSA) convention and prevents the use of non-serializable values. The style guide at [`docs/usage/reducing-boilerplate.md`](https://github.com/reduxjs/redux/blob/main/docs/usage/reducing-boilerplate.md) explicitly recommends using string constants (never `Symbol`s) for action types to maintain this compatibility.

## Type-Level Constraints in TypeScript

Beyond runtime checks, the constraint is cemented at the type-system level in [`src/types.ts`](https://github.com/reduxjs/redux/blob/main/src/types.ts). The `UnknownAction` type (which replaces the legacy `AnyAction`) defines the `type` property strictly as `string`:

```typescript
interface UnknownAction {
  type: string
}

```

This TypeScript definition prevents developers from mistakenly typing actions with non-string type values during development, catching errors before they reach runtime.

## Valid vs. Invalid Action Examples

The following examples demonstrate the runtime constraints enforced by the Redux store:

```javascript
// ✅ Valid action – type is a string
store.dispatch({ type: 'todos/add', payload: { text: 'Buy milk' } })

// ❌ Invalid action – type is missing
store.dispatch({ payload: { text: 'Missing type' } }) // throws: "Actions must have a type property"

 // ❌ Invalid action – type is not a string
store.dispatch({ type: Symbol('add'), payload: {} }) // throws: "Action.type must be a string"

// ❌ Invalid action – action is not a plain object
store.dispatch(() => ({ type: 'funcAction' })) // throws: "Actions must be plain objects"

```

## Summary

- **Action type values in Redux must be strings** — Symbols, objects, or functions are rejected at runtime.
- **`store.dispatch()` validates actions** in [`src/createStore.ts`](https://github.com/reduxjs/redux/blob/main/src/createStore.ts), throwing errors for malformed actions.
- **TypeScript definitions** in [`src/types.ts`](https://github.com/reduxjs/redux/blob/main/src/types.ts) enforce these constraints at compile time through the `UnknownAction` type.
- **String types enable serialization**, making time-travel debugging and state persistence possible.
- **The migration guide and style guide** at [`docs/usage/migrations/migrating-rtk-2.md`](https://github.com/reduxjs/redux/blob/main/docs/usage/migrations/migrating-rtk-2.md) and [`docs/usage/reducing-boilerplate.md`](https://github.com/reduxjs/redux/blob/main/docs/usage/reducing-boilerplate.md) document these requirements as best practices.

## Frequently Asked Questions

### Can I use Symbols for action types in Redux?

No, Redux explicitly prohibits using `Symbol` values for action types. According to the style guide in [`docs/usage/reducing-boilerplate.md`](https://github.com/reduxjs/redux/blob/main/docs/usage/reducing-boilerplate.md), Symbols are non-serializable and break Redux DevTools functionality. The runtime check in [`src/createStore.ts`](https://github.com/reduxjs/redux/blob/main/src/createStore.ts) will throw an error if you attempt to dispatch an action with a Symbol type.

### What happens if I dispatch an action without a type property?

The `store.dispatch()` method will throw a runtime error stating "Actions must have a type property." This check occurs before the action reaches any reducers or middleware, preventing untyped actions from corrupting the state management flow.

### Are there any exceptions to the string-only rule for action types?

No, there are no exceptions in the core Redux library. Every action dispatched to a standard Redux store must have a string `type` value. This universal constraint ensures compatibility with the ecosystem of middleware, enhancers, and developer tools that expect serializable action metadata.

### How do TypeScript types enforce action type constraints?

The `UnknownAction` interface defined in [`src/types.ts`](https://github.com/reduxjs/redux/blob/main/src/types.ts) explicitly types the `type` property as `string`, replacing the more permissive legacy `AnyAction` type. This means TypeScript will flag compilation errors when you attempt to define actions with non-string type values, catching potential violations before runtime.