npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@ngfk/ts-redux

v2.1.0

Published

Typescript wrapper for Redux. Type safety and intellisense when creating reducers and dispatching actions.

Downloads

23

Readme

TS-Redux

Typescript wrapper for Redux. Type safety and intellisense when creating reducers and dispatching actions.

npm version Downloads Travis CI

Installation

npm install @ngfk/ts-redux redux

Usage

TLDR

  1. Define state structure
  2. Map actions
  3. Create reducers
  4. Create store

1. Define state structure

Using TS-Redux starts with defining the state structure. An immutable state can be accomplished in typescript by marking all properties as readonly.

interface Todo {
    readonly id: number;
    readonly text: string;
    readonly completed: boolean;
}

enum Filter {
    All,
    Completed,
    Active
}

interface State {
    readonly todos: Todo[];
    readonly filter: Filter;
}

2. Map actions

After defining the state you need to create an action map. This is done using an interface with the action type as key and the payload type as value.

interface TodoActionMap {
    TODO_ADD: { id: number; text: string };
    TODO_TOGGLE: number;
    TODO_REMOVE: undefined;
}

interface FilterActionMap {
    FILTER_SET: Filter;
}

interface ActionMap extends TodoActionMap, FilterActionMap {}

The first entry in TodoActions represents an action with TODO_ADD as its type with a payload object holding an id and some text. Note that in order to combine mappings into a single larger mapping we can create an interface that extends the other mappings.

Define action creators (optional)

When using Redux in combination with React you may want to define action creators to use with react-redux. To define these action creators you can use the ActionFactory. See the React example project.

const todoFactory = new ActionFactory<TodoActionMap>();
const todoActionCreators = {
    todoAdd: todoFactory.creator('TODO_ADD'),
    todoToggle: todoFactory.creator('TODO_TOGGLE'),
    todoRemove: todoFactory.creator('TODO_REMOVE')
};

const filterFactory = new ActionFactory<FilterActionMap>();
const filterActionCreators = {
    setFilter: filterFactory.creator('FILTER_SET')
};

3. Create reducers

With the state and the actions defined we can create our reducers. TS-Redux provides a createReducer function, this function takes the initial state as the first parameter and a 'sub-reducer' mapping as the second parameter. A sub-reducer can be compared to one case in a standard Redux reducer, the sub-reducer takes the state and the action payload and returns the new state. The compiler will only accept the mapped sub-reducers if every defined action is mapped to a sub-reducer. At this stage the compiler knows the state and payload types.

const todoReducer = createReducer<Todo[], TodoActionMap>([], {
    TODO_ADD: (state, payload) => [
        ...state,
        { id: payload.id, text: payload.text, completed: false }
    ],
    TODO_TOGGLE: (state, payload) => {
        return state.map(
            todo =>
                todo.id === payload
                    ? { ...todo, completed: !todo.completed }
                    : todo
        );
    },
    TODO_REMOVE: (state, payload) => {
        return state.filter(todo => todo.id !== payload);
    }
});

const filterReducer = createReducer<Filter, FilterActionMap>(Filter.All, {
    FILTER_SET: (_, payload) => payload
});

After creating our reducers we can combine them with the combineReducers function. This function will only accept its parameter if all the required properties are mapped to the correct reducer.

const reducer = combineReducers<State>({
    todos: todoReducer,
    filter: filterReducer
});

If you need more control when creating reducers you can also use the ReducerBuilder class. This builder has the same type checks in place but does not require you to define an initial state or to handle every mapped action.

4. Create store

With the root reducer we can finally create our store. We provide the state type and the action mapping while creating our store so that the store knows which action types can be dispatched, and what the corresponding payload type is.

The resulting store is a TS-Redux store implementing the default Redux store. This means that the dispatch method can still be used to accept any action. However, to ensure type safety the store provides an action method to select one of the defined actions which can then be dispatched with the corresponding payload.

const store = createStore<State, ActionMap>(reducer);

// No type safety
store.dispatch({ type: 'ANYTHING' });

// Type safe
store.dispatch('TODO_ADD', { id: 1, text: 'My first TODO!' });
store.dispatch('TODO_TOGGLE', 1);

Example projects