{"id":12235,"library":"typescript-fsa-redux-thunk","title":"TypeScript FSA Utilities for Redux Thunk","description":"typescript-fsa-redux-thunk is a utility library that bridges the gap between `typescript-fsa`'s strongly typed Flux Standard Action (FSA) creators and `redux-thunk` for handling asynchronous operations in Redux applications. It provides an `asyncFactory` to easily define typed async action creators, streamlining the process of dispatching `started`, `done`, and `failed` actions that conform to the FSA specification. The current stable version is 2.10.2. While the release cadence isn't explicitly stated, the project appears actively maintained with recent updates, though the latest npm publish was 5 years ago for 2.10.2. A key differentiator is its tight integration with `typescript-fsa`, allowing developers to leverage type safety throughout their async Redux action flows, including custom error types. It also includes `thunkToAction` for easier integration with `bindActionCreators`.","status":"active","version":"2.10.2","language":"javascript","source_language":"en","source_url":"https://github.com/xdave/typescript-fsa-redux-thunk","tags":["javascript","action","action creator","flux standard action","redux","redux-thunk","thunk","typescript","typescript-fsa"],"install":[{"cmd":"npm install typescript-fsa-redux-thunk","lang":"bash","label":"npm"},{"cmd":"yarn add typescript-fsa-redux-thunk","lang":"bash","label":"yarn"},{"cmd":"pnpm add typescript-fsa-redux-thunk","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Core Redux library for state management.","package":"redux","optional":false},{"reason":"Redux middleware for handling asynchronous actions.","package":"redux-thunk","optional":false},{"reason":"Library for creating type-safe Flux Standard Actions.","package":"typescript-fsa","optional":false}],"imports":[{"note":"`asyncFactory` is the primary export for creating asynchronous Redux Thunk actions using `typescript-fsa` patterns.","wrong":"const asyncFactory = require('typescript-fsa-redux-thunk').asyncFactory;","symbol":"asyncFactory","correct":"import { asyncFactory } from 'typescript-fsa-redux-thunk';"},{"note":"`thunkToAction` is a utility for casting ThunkActionCreators, often used with `bindActionCreators`.","wrong":"const thunkToAction = require('typescript-fsa-redux-thunk').thunkToAction;","symbol":"thunkToAction","correct":"import { thunkToAction } from 'typescript-fsa-redux-thunk';"},{"note":"While `typescript-fsa-redux-thunk` is a companion, the base `actionCreatorFactory` comes from `typescript-fsa` itself and is a default import.","wrong":"import { create } from 'typescript-fsa';","symbol":"create","correct":"import actionCreatorFactory from 'typescript-fsa';"}],"quickstart":{"code":"import 'isomorphic-fetch'; // For Node.js environments\nimport { createStore, applyMiddleware, AnyAction } from 'redux';\nimport thunkMiddleware, { ThunkMiddleware } from 'redux-thunk';\nimport { reducerWithInitialState } from 'typescript-fsa-reducers';\nimport actionCreatorFactory from 'typescript-fsa';\nimport { asyncFactory } from 'typescript-fsa-redux-thunk';\n\ninterface LoginParams {\n  email: string;\n  password: string;\n}\ninterface UserToken {\n  token: string;\n}\nclass CustomError extends Error {}\n\ninterface State {\n  title: string;\n  userToken: UserToken;\n  loggingIn?: boolean;\n  error?: CustomError;\n}\n\nconst create = actionCreatorFactory('examples');\nconst createAsync = asyncFactory<State>(create);\n\nconst changeTitle = create<string>('Change the title');\n\nconst login = createAsync<LoginParams, UserToken, CustomError>(\n  'Login',\n  async (params, dispatch) => {\n    const url = `https://reqres.in/api/login`;\n    const options: RequestInit = {\n      method: 'POST',\n      body: JSON.stringify(params),\n      headers: {\n        'Content-Type': 'application/json; charset=utf-8',\n      },\n    };\n    const res = await fetch(url, options);\n    if (!res.ok) {\n      throw new CustomError(`Error ${res.status}: ${res.statusText}`);\n    }\n\n    dispatch(changeTitle('You are logged-in'));\n\n    return res.json();\n  },\n);\n\nconst initial: State = {\n  title: 'Please login',\n  userToken: {\n    token: '',\n  },\n};\n\nconst reducer = reducerWithInitialState(initial)\n  .case(changeTitle, (state, title) => ({\n    ...state,\n    title,\n  }))\n  .case(login.async.started, (state) => ({\n    ...state,\n    loggingIn: true,\n    error: undefined,\n  }))\n  .case(login.async.failed, (state, { error }) => ({\n    ...state,\n    loggingIn: false,\n    error,\n  }))\n  .case(login.async.done, (state, { result: userToken }) => ({\n    ...state,\n    userToken,\n    loggingIn: false,\n    error: undefined,\n  }));\n\n(async () => {\n  const thunk: ThunkMiddleware<State, AnyAction> = thunkMiddleware;\n  const store = createStore(reducer, applyMiddleware(thunk));\n  console.log('Initial state:', store.getState().title);\n\n  try {\n    await store.dispatch(login({ email: 'eve.holt@reqres.in', password: 'cityslicka' }));\n    const { title, userToken } = store.getState();\n    console.log('Logged in state:', title, userToken);\n  } catch (err) {\n    console.error('Login failed:', err);\n  }\n})();","lang":"typescript","description":"This example demonstrates how to create a type-safe asynchronous login action using `asyncFactory`, set up a Redux store with `redux-thunk`, and handle the action's lifecycle (started, failed, done) in a reducer."},"warnings":[{"fix":"Review the official documentation for 2.x to adapt `asyncFactory` usage and return types. Explicitly return a Promise from your worker function if a promise result is desired.","message":"Version 2.x introduces breaking changes from 1.x, particularly around the assumption of the result type for async actions. The API has been simplified, and the result type is no longer always assumed to be a Promise.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Ensure `applyMiddleware(thunkMiddleware)` is used when creating your Redux store, and that `thunkMiddleware` is correctly typed as `ThunkMiddleware<State, AnyAction>`.","message":"`redux-thunk` middleware must be correctly applied to your Redux store for `typescript-fsa-redux-thunk`'s async actions to function. Dispatching a thunk without the middleware will lead to type errors or runtime issues.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"When creating the store, explicitly define `ThunkMiddleware<State, AnyAction>`. For components, consider creating a custom typed `useAppDispatch` hook if using React-Redux, following Redux Toolkit's recommendations.","message":"Properly typing the `dispatch` function within Redux thunks, especially when dispatching other thunks or specific actions, requires careful configuration using `ThunkMiddleware` or explicitly defining `AppDispatch`.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Verify that `typescript-fsa` is installed at version `3.x` or higher (`npm install typescript-fsa@^3`).","message":"This library relies on `typescript-fsa` for action creator factories. Ensure you are using `typescript-fsa` version 3.x or newer, as specified in peer dependencies, to avoid type conflicts or unexpected behavior.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"If manually importing `redux-thunk` directly, use `import { thunk } from 'redux-thunk';` instead of the default import. Redux Toolkit's `configureStore` handles this automatically.","message":"Redux-Thunk itself has undergone changes, particularly in Redux Thunk 3.0 (released with Redux 5.0 and RTK 2.0), where the default export was removed in favor of named exports `thunk` and `withExtraArgument`. While `typescript-fsa-redux-thunk` might abstract this, be aware if directly interacting with `redux-thunk`'s exports.","severity":"deprecated","affected_versions":">=2.10.0 (if using Redux Thunk 3.0)"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Ensure `redux-thunk` middleware is correctly applied: `createStore(reducer, applyMiddleware(thunkMiddleware))`.","cause":"Attempting to dispatch a Redux Thunk action without the `redux-thunk` middleware being applied to the Redux store.","error":"Argument of type 'ThunkAction<any, any, any, AnyAction>' is not assignable to parameter of type 'AnyAction'. Property 'type' is missing in type 'ThunkAction' but required in type 'AnyAction'."},{"fix":"For Node.js environments, install a polyfill like `isomorphic-fetch` (`npm install isomorphic-fetch @types/isomorphic-fetch`) and import it: `import 'isomorphic-fetch';`.","cause":"The `fetch` API is used in the quickstart example, but it's a browser API not natively available in Node.js, and its types might be missing in some TypeScript configurations.","error":"Cannot find name 'fetch'. Do you need to install type definitions for a global API such as 'fetch'?"},{"fix":"Verify that your `reducerWithInitialState` or similar reducer setup includes `.case()` for all `started`, `done`, and `failed` actions created by `asyncFactory`, with the correct action type string.","cause":"A `typescript-fsa` action (like `login.async.done`) was dispatched, but the corresponding `.case()` handler is missing or incorrectly named in the reducer.","error":"Error: Reducer for action 'examples/Login_DONE' not found."}],"ecosystem":"npm"}