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

typedstate

v1.3.4

Published

> A React/Redux wrapper to reduce boilerplate and increase type safety and productivity

Downloads

5

Readme

TypedState

A React/Redux wrapper to reduce boilerplate and increase type safety and productivity

Why?

After using React with Redux, I found that using connect, creating reducers, and sagas required a lot of boilerplate.
In order to get the type safety I wanted, I would regularly have to modify old code to do so.

TypedState is an attempt to reduce the amount of effort introducing React and Redux into a project and to make it easier to use without being burdened by passing types around.

Project Goals

  • Provide a very low barrier for entry to React+Redux
  • Provide complete type safety in components, reducers, and sagas
  • Reduce boilerplate in React/Redux projects
  • Maintain a small and discoverable API to ensure high developer experience

Benefits

Reducers, sagas, and components gain a huge amount of type safety and type inference.
Action types, state

Example Setup

You will still need to add React and Redux dependencies!

  • react
  • redux
  • react-redux
  • react-dom

See the example folder for a more complete example project.

API

createStore()

Returns setup and saga functions

import { createStore } from 'typedstate'

function createStore(name: string, reducers: { [key: string]: Reducer })

createReducer()

Returns handle and reducer functions.
The reducer must be exported and passed to the createStore function.

import { createReducer } from 'typedstate'

function createReducer<State, Action>(initState: State, handler?: HandlerBody)

setup()

Returns the Redux store and the withState and withDispatch hooks.
Think of withState as a wrapper of the react-redux connect function.

See examples/App.tsx for several examples.

Example

See the example/ folder for a more complete example

Creating a Store

The amount of code required to create the store is small and less complicated.
You no longer need to maintain a union type of all of your actions nor an interface of your application state.
Simply adding a reducer will provide all of the type safety you need when using store and withState().

import { createStore } from 'typedstate'
import * as user from './user'
import * as game from './game'

const { setup, saga } = createStore('my app', {
  user: user.reducer,
  game: game.reducer,
})

const { store, withDispatch, withState } = setup()

export { saga, store, withDispatch, withState }

Creating a Reducer

Creating reducers and sagas is fast, easy, and declarative.

import { createReducer } from 'typedstate'

export { reducer }

interface State {
  state: 'init' | 'loading' | 'loaded'
  name?: string
  loggedIn: boolean
  error?: string
}

type Action =
  | { type: 'USER_REQUEST_LOGIN'; username: string; password: string }
  | { type: 'USER_RECEIVE_LOGIN'; name?: string; error?: string }
  | { type: 'USER_REQUEST_LOGOUT' }

const { reducer, handle } = createReducer<State, Action>({ state: 'init', loggedIn: false })

handle('USER_REQUEST_LOGIN', { error: undefined, name: undefined, state: 'loading' })
handle('USER_RECEIVE_LOGIN', (_state, action) => {
  return {
    state: 'loaded',
    name: action.name,
    error: action.error,
    loggedIn: action.error === undefined,
  }
})

handle('USER_REQUEST_LOGOUT', { name: undefined, error: undefined, loggedIn: false })

Alternative way of Creating a Reducer

import { createReducer } from 'typedstate'

interface State {
  state: 'init' | 'loading' | 'loaded'
  name?: string
  loggedIn: boolean
  error?: string
}

type Action =
  | { type: 'USER_REQUEST_LOGIN'; username: string; password: string }
  | { type: 'USER_RECEIVE_LOGIN'; name?: string; error?: string }
  | { type: 'USER_REQUEST_LOGOUT' }

export const { reducer } = createReducer<State, Action>(
  { state: 'init', loggedIn: false },
  {
    USER_REQUEST_LOGIN: () => ({ error: undefined, name: undefined, state: 'loading' }),
    USER_RECEIVE_LOGIN: (_, action) => {
      return {
        state: 'loaded',
        name: action.name,
        error: action.error,
        loggedIn: action.error === undefined,
      }
    },
    USER_REQUEST_LOGOUT: () => ({ name: undefined, error: undefined, loggedIn: false }),
  }
)

Creating a Component

Creating components takes less code

import * as React from 'react'
import { withState } from '/store'

export const Profile = withState(
  ({ user }) => user,
  ({ state, name, error, loggedIn, dispatch }) => {
    const login = () => dispatch({ type: 'USER_REQUEST_LOGIN', username, password })
    const logout = () => dispatch({ type: 'USER_REQUEST_LOGOUT' })
    const [username, setUsername] = React.useState('')
    const [password, setPassword] = React.useState('')

    return <div>Create your component as you normally would</div>
  }
)