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

tsdux

v4.0.1

Published

Type-safe Redux utilities for TypeScript

Downloads

184

Readme

tsdux

npm latest version npm total download github license github latest tag github commit from latest travis status codecov coverage

Type-safe Redux Utils for TypeScript!

Table of Contents

How To Install

npm install --save redux tsdux

If you use redux-observable or use RxJS with redux, you also might have interest in tsdux-observable which includes some basic utilities to use TSdux with Observables.

npm install --save rxjs tsdux-observable

How To Use

// mysection.ts
import { action, payload, union } from 'tsdux';

interface MySectionState {
  log?: string;
  id: number;
}

// Make action creators
export const MyAction = action('myapp/mysection/MY_ACTION', props<{ error?: string }>());
export const YourAction = action('myapp/mysection/YOUR_ACTION', payload<{ id: number }>());

const Action = union([
  MyAction,
  YourAction,
]);
type Action = typeof Action;

const initialState: MySectionState = {
  id: 0,
};
export default function reducer(state: MySectionState = initialState, action: ActionType): MySectionState {
  switch(action.type) {
  case MyAction.type:
    return {
      ...state,
      log: action.error,
    };
  case YourAction.type:
    return {
      ...state,
      id: action.payload.id,
    };
  default:
    return state;
  }
}
// At other part that uses redux
import { MyAction, YourAction } from './mysection';
import { store } from './store';

store.dispatch(MyAction('abcd'));
store.dispatch(YourAction({ id: 5 }));

Prior Arts

This library is highly inspired by ts-action. However, it uses Object.setPrototypeOf in its code, and it is really, really bad to performace (see MDN) and have some runtime overheads on the ActionCtor instances. This library is intended to be more fast, and be more lighter (therefore, have less APIs...) than ts-action (At least this does not use Object.setPrototypeOf!). If you find any codes those hurt performance, please report an issue.

API

API Types

Types used in this library.

TypeOnlyAction

Action without any extra properties.

type TypeOnlyAction<T extends string> = {
  type: T;
}

PropsAction

Action with extra properties.

type PropsAction<T extends string, P extends object = {}> = {
  type: T;
} & P;

PayloadAction

Action with payload property. This action is easier to create than PropsAction, although this also has its own cons.

type PayloadAction<T extends string, P = {}> = {
  type: T;
  payload: P;
}

TypeOnlyActionCreator

ActionCreator made by action function. This ActionCreator creates TypeOnlyAction.

interface TypeOnlyActionCreator<T extends string> {
  (): TypeOnlyAction<T>;
  type: T;
  action: TypeOnlyAction<T>;
  create(): TypeOnlyAction<T>;
}

PropsActionCreator

This ActionCreator creates PropsAction.

interface PropsActionCreator<T extends string, P extends object = {}> {
  (props: P): PropsAction<T, P>;
  type: T;
  action: PropsAction<T, P>;
  create(props: P): PropsAction<T, P>;
}

PayloadActionCreator

This ActionCreator creates PayloadAction.

interface PayloadActionCreator<T extends string, P = {}> {
  (payload: P): PayloadAction<T, P>;
  type: T;
  action: PayloadAction<T, P>;
  create(payload: P): PayloadAction<T, P>;
}

Action util functions

Functions for defining an action (or rather an action creator). Defined action creators are used to define reducer.

action

function action<T extends string>(type: T): TypeOnlyActionCreator<T>;
function action<T extends string, P extends object = {}>(type: T, p: PropsOpt<P>): PropsActionCreator<T, P>;
function action<T extends string, P = {}>(type: T, p: PayloadOpt<P>): PayloadActionCreator<T, P>;

action is for creating an ActionCreator. ActionCreator is object used for this library. You can create action by calling ActionCreator itself or calling actionCreator.create method.

const FixNote = action('FixNote');
const fixNote0 = FixNote.create();
const fixNote1 = FixNote();
console.log(fixNote0); // { type: 'FixNote' }
console.log(fixNote1); // { type: 'FixNote' }
switch (action.type) {
case FixNote.type:
  // ... fix note
default:
  return state;
}

However, if you cannot define payload, this action is useless. You can define it using payload function.

payload

function payload<P = {}>(): PayloadOpt<P>

payload is for creating a payload argument (second argument) of action function.

const AddNote = action('AddNote', payload<string>());
const addNote = AddNote('This is a new note');
console.log(addNote); // { type: 'AddNote', payload: 'This is a new note' }

props

function props<P extends object = {}>(): PropsOpt<Omit<P, 'type'>>

props is for creating a props argument (second argument) of action function.
The difference between props and payload is that props injects additional data to action as property, where payload set additional data to payload of action. To get more clear understanding, see following example.

const ActionFromProps = action('Example0', props<{ x: number }>());
const ActionFromPayload = action('Example1', payload<{ x: number }>());

console.log(ActionFromProps({ x: 5 })); // { type: 'Example0', x: 5 }
console.log(ActionFromPayload({ x: 5 })); // { type: 'Example1', payload: { x: 5 } }

const OnlyForPayload = action('Example2', payload<string>());
// Following codes emit an error.
const ThisDoesNotWork = action('Example3', props<string>()); // There's no way to inject 'string' into action.

console.log(OnlyForPayload('abc')); // { type: 'Example2', payload: 'abc' }
const AddError = action('AddError', props<{ error?: string }>());
const addError0 = AddError({});
const addError1 = AddError({ error: 'New error' });
console.log(addError0); // { type: 'AddError' }
console.log(addError1); // { type: 'AddError', error: 'New error' }

Action type util functions

Functions to define union type (or to do other type-related things).

union

function union<AC extends ActionCreator<string, any>>(arg: Array<AC>): AC['action'];

To define the type including all actions, you need to use this function. This union type is useful when you define a reducer without subreducer and reducer functions.

const NoteActions = union([FixNote, AddNote]);

function reducer(state: State = { notes: [] }, action: NoteActions) {
  switch(action.type) {
  case FixNote.type:
    // ...
  case AddNote.type:
    // ...
  }
}

isType

function isType<AC extends ActionCreator<string, any>>(
  action: AnyAction, actionCreators: AC | Array<AC>,
): action is AC['action']

To check an action is specific type or not, you can use this function.

function reducer(state: State = { notes: [] }, action: NoteActions) {
  if (isType(action, FixNote)) {
    // ...
  } eles if (isType(action, AddNote)) {
    // ...
  } // ...
}

Reducer util functions

Functions for define redux reducer.

subreducer

function subreducer<S, T extends string, P extends object>(
  action: ActionCreator<T, P>, handler: Subreducer<S, T, P>['handler'],
): Subreducer<S, T, P>

Function to define a reducer for specific action.

const fixNoteReducer = subreducer(FixNote, function (state) {
  return {
    ...state,
  });
});

const addNoteReducer = subreducer(AddNote, function (state, payload) {
  return {
    ...state,
    notes: [...state.notes, payload],
  });
});

These Subreducers can be merged using reducer function.

reducer

function reducer<S, SR extends Subreducer<S, string, any>>(
  initialState: S, subreducers: Array<SR>,
): Reducer<S>

Function to define a reducer by merging Subreducer cases.

export reducer({ notes: [] }, [fixNoteReducer, addNoteReducer]);

Code above is similar with

export function reducer(state = { notes: [] }, action) {
  switch (action.type) {
  case FixNote.type:
    //...
  case AddNote.type:
    //...
  // Code above includes following default case too.
  default:
    return state;
  }
}

Author

Junyoung Clare Jang @Ailrun