typescript-action-creator

Helper that creates simple React and Redux compatible action creators that work well with Typescript.


Keywords
react, redux, action, actions, typescript
License
MIT
Install
npm install typescript-action-creator@0.8.0

Documentation

Typescript Action Creator

NPM License Coverage Build

Helper that creates simple React and Redux compatible action creators that work well with Typescript.

Installation

npm install typescript-action-creator --save-dev

Example

Create a simple action creator in one line:

import { createAction } from 'typescript-action-creator';

const setLoading = createAction('SET_LOADING');

setLoading(); // { type: 'SET_LOADING' }

Or create an action creator with payload in one line:

import { createAction } from 'typescript-action-creator';

const setProgress = createAction('SET_PROGRESS', (progress: number) => progress);

setProgress(50); // { type: 'SET_PROGRESS', payload: 50 }

In your component you can use this action creators as following:

import React, { useCallback } from 'react';
import { useDispatch } from 'react-redux';

import { setLoading } from './actions/setLoading';
import { setProgress } from './actions/setProgress';

const MyComponent = () => {
    const dispatch = useDispatch();

    const onClick = useCallback(() => {
        dispatch(setLoading()); // { type: 'SET_LOADING' }
        dispatch(setProgress(50)); // { type: 'SET_PROGRESS', payload: 50 }
    }, [dispatch]);

    return <button onClick={onClick}>Example</button>;
};

We also provide a nice isActionType method that is useful in reducers. The isActionType method is a Typescript Type Guard: It will check if the action is a result of the action creator. If so, then the action is automatically type casted to the correct action type, including the payload.

import { Action, isActionType } from 'typescript-action-creator';
import { State } from './State';

import { setLoading } from './actions/setLoading';
import { setProgress } from './actions/setProgress';

const reducer = (state: State, action: Action) => {

    if (isActionType(action, setLoading)) {
        return { ...state, loading: true };
    }

    if (isActionType(action, setProgress)) {
        const progress = action.payload; // This is automatically a number!
        return { ...state, progress };
    }

    return state;
};

Each action creator also exports a 'TYPE' property. This can be useful in places where you need the string type but do not want to use a hardcoded string. For instance when we use Redux Saga's:

import { all, takeEvery } from 'redux-saga/effects';
import { createAction } from 'typescript-action-creator';

const createItem = createAction('CREATE_ITEM');
const deleteItem = createAction('DELETE_ITEM');
const updateItem = createAction('UPDATE_ITEM');

function* createItemSaga() { ... }
function* deleteItemSaga() { ... }
function* updateItemSaga() { ... }

function* itemSaga() {
    yield all([
        takeEvery(createItem.TYPE, createItemSaga),
        takeEvery(deleteItem.TYPE, deleteItemSaga),
        takeEvery(updateItem.TYPE, updateItemSaga),
    ]);
}

In a nutshell, here are all the types and what they return:

import { Action, createAction, isActionType } from 'typescript-action-creator';

import { State } from './State';

const setLoading = createAction('SET_LOADING');
const setProgress = createAction('SET_PROGRESS', (progress: number) => progress);

type SetLoadingAction = ReturnType<typeof setLoading>; // Action<'SET_LOADING'>
type SetProgressAction = ReturnType<typeof setProgress>; // Action<'SET_PROGRESS', number>

const setLoadingAction = setLoading(); // { type: 'SET_LOADING' }
const setProgressAction = setProgress(50); // { type: 'SET_PROGRESS', payload: 50 }

console.info(setLoadingAction.type); // 'SET_LOADING'
console.info(setProgressAction.type); // 'SET_PROGRESS'
console.info(setProgressAction.payload); // 50

console.info(setLoading.TYPE); // 'SET_LOADING'
console.info(setProgress.TYPE); // 'SET_PROGRESS'

const reducer = (state: State, action: Action) => {
    if (isActionType(action, setLoading)) {
        return { ...state, loading: true };
    }

    if (isActionType(action, setProgress)) {
        const progress = action.payload; // 50
        return { ...state, progress };
    }

    return state;
};