• Stars
    star
    315
  • Rank 132,951 (Top 3 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created over 5 years ago
  • Updated about 2 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

An attempt to bring better TypeScript typing to redux-saga.

Typed Redux Saga

npm Build Status Type Coverage codecov Snyk Vulnerabilities for GitHub Repo

An attempt to bring better TypeScript typing to redux-saga.

Requires TypeScript 3.6 or later.

Installation

# yarn
yarn add typed-redux-saga

# npm
npm install typed-redux-saga

Usage

Let's take the example from https://redux-saga.js.org/#sagasjs

Before

import { call, all } from "redux-saga/effects";
// Let's assume Api.fetchUser() returns Promise<User>
// Api.fetchConfig1/fetchConfig2 returns Promise<Config1>, Promise<Config2>
import Api from "...";

function* fetchUser(action) {
  // `user` has type any
  const user = yield call(Api.fetchUser, action.payload.userId);
  ...
}

function* fetchConfig() {}
  // `result` has type any
  const result = yield all({
    api1: call(Api.fetchConfig1),
    api2: call(Api.fetchConfig2),
  });
  ...
}

After

// Note we import `call` from typed-redux-saga
import { call, all } from "typed-redux-saga";
// Let's assume Api.fetchUser() returns Promise<User>
// Api.fetchConfig1/fetchConfig2 returns Promise<Config1>, Promise<Config2>
import Api from "...";

function* fetchUser(action) {
  // Note yield is replaced with yield*
  // `user` now has type User, not any!
  const user = yield* call(Api.fetchUser, action.payload.userId);
  ...
}

function* fetchConfig() {}
  // Note yield is replaced with yield*
  // `result` now has type {api1: Config1, api2: Config2}
  const result = yield* all({
    api1: call(Api.fetchConfig1),
    api2: call(Api.fetchConfig2),
  });
  ...
}

Babel Macro

You can use the built-in babel macro that will take care of transforming all your effects to raw redux-saga effects.

Install the babel macros plugin:

yarn add --dev babel-plugin-macros

Modify your import names to use the macro:

import {call, race} from "typed-redux-saga/macro";

// And use the library normally
function* myEffect() {
  yield* call(() => "foo");
}

The previous code will be transpiled at compile time to raw redux-saga effects:

import {call, race} from "redux-saga/effects";

function* myEffect() {
  yield call(() => 'foo');
}

This gives you all the benefits of strong types during development without the overhead induced by all the calls to typed-redux-saga's proxies.

ESLint Rules

In order to avoid accidentally importing the original effects instead of the typed effects, you can use this ESLint plugin: https://github.com/jambit/eslint-plugin-typed-redux-saga

It includes an auto-fix option, so you can use it to easily convert your codebase from redux-saga to typed-redux-saga!

Credits

Thanks to all the contributors and especially thanks to @gilbsgilbs for his huge contribution.

See Also