redux-typed-actions
    TypeScript icon, indicating that this package has built-in type declarations

    0.1.5 • Public • Published

    Redux Typed Actions

    An opinionated approach to type actions and their payload in Redux with statically type checking in Typescript. This approach removes the most possible boilerplate of your actions & their creators in React and any other frameworks.

    Installation

    Let's get started by installing it from npm repository

    $ npm install --save-dev redux-typed-actions

    or from yarn repository

    $ yarn add --dev redux-typed-actions

    Usage

    Let's do a quick example to see how this approach can improve type checking of redux actions

    1. You have an ItemX interface:
      feature-x.types.ts

      export interface ItemX {
        title: string;
      }
    2. First we define our actions:
      feature-x.actions.ts

      import { defineAction, defineScenarioAction, defineSymbolAction } from 'redux-typed-actions';
      import { ItemX } from './feature-x.types';
       
      // For this action we will have number as our payload
      export const FeatureXAddTicketAction = defineAction<number>('[Feature X] Add Ticket');
       
      /**
       *  This action is special, it's called a scenario-like action
       *  It notifies the system with status of a process covering from start to end.
       *  You can get Start/Success/Failure/Cancel from this action generator/creator
       *  There are 4 types that belong respectively to Start/Success/Failure/Cancel
       *  Note: The default type for payload of success and failure is
       *  string so you can skip them like `defineScenarioAction('MyActionName')`
       */
      export const FeatureXLoadAction = defineScenarioAction<never, ItemX[], string>('[Feature X] Load');
       
      // Let's have a symbol action just for fun
      export const FeatureXDummySymbolAction = defineSymbolAction<ItemX[]>('[Feature X] Dummy Started');

      Note: You can setup your own suffix for Start/Success/Failure/Cancel of scenario actions as following example:

      import { factory } from 'redux-typed-actions';
       
      // You must set them before defining actions
      factory.setSuffixes({
        start: '_REQUEST',
        cancel: '_CANCEL',
        success: '_SUCCESS',
        failure: '_FAILURE',
      });
    3. Now we dispatch our actions:
      feature-x.component.ts

      import { ItemX } from './feature-x.types';
      import { FeatureXAddTicketAction, FeatureXLoadAction } from '../feature-x.actions';
      ...
       
      // React Redux solution to replace action creators:
      // Let's define our component's state
      interface FeatureXProps {
        ...
        addTicket: typeof FeatureXAddTicketAction.strictGet; // StrictGet makes the payload mandatory
      }
       
      ...
      class FeatureX extends React.Component<FeatureXProps> {
        ...
        addTicket = () => this.props.addTicket(1) // <- Static type checking
       
        render() {
          return (<button onClick={this.addTicket}>Add one ticket</button>); // />
        }
      }
       
      // Let's hook the action to redux, and we're done
      export default connect(undefined, { addTicket: FeatureXAddTicketAction.strictGet })(FeatureX);
       
       
      // All Typescript frameworks:
      // Dispatching a simple action
      store.dispatch(FeatureXAddTicketAction.get(100));
       
      // Let's start our scenario by dispatching our action
      store.dispatch(FeatureXLoadAction.get());
       
      // Now we dispatch the success action
      const payload: ItemX[] = [{ title: 'item 1' }, { title: 'item 2' }];
      dispatch(FeatureXLoadAction.success.get(payload));
       
      // or simply a failure
      dispatch(FeatureXLoadAction.failure.get('It failed because...'));
    4. Now let's take a look at our reducers to see how we can type check the payloads:
      feature-x.reducers.ts

      import { PlainAction } from 'redux-typed-actions';
      import { ItemX } from './feature-x.types';
      import { FeatureXLoadAction } from '../feature-x.actions';
       
      export interface ItemXState {
        items: ItemX[];
        loading: boolean;
      }
       
      export function reducer(state: ItemXState = InitialState, action: PlainAction): ItemXState {
        if (FeatureXLoadAction.is(action)) {
          // Within this branch our action variable has the right typings
          return {
            ...state,
            loading: true,
          };
       
        } else if (FeatureXLoadAction.success.is(action)) {
          return {
            ...state,
            loading: false,
            items: action.payload, // <- Here we are checking types strongly
          };
       
        } else {
          return state;
        }
      }
    5. If you're fan of redux-observables then this part is for you:
      feature-x.epics.ts

      (action$, store) => action$
         .ofType(FeatureXLoadAction.type)
         .map(action => FeatureXLoadAction.cast(action)) // <- from here we will have all the typings right :)
         .switchMap(action => Service()
             .map(value => FeatureXLoadAction.success.get(repos))
             .catch(() => Observable.of(FeatureXLoadAction.failure.get('Oops something went wrong!'))));
    6. That's it

    Take a look at React or Angular examples for a closer look.

    Install

    npm i redux-typed-actions

    DownloadsWeekly Downloads

    41

    Version

    0.1.5

    License

    MIT

    Last publish

    Collaborators

    • aminpaks