Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

tsdux

Package Overview
Dependencies
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

tsdux

Type-safe Redux utilities for TypeScript

  • 4.0.1
  • latest
  • Source
  • npm
  • Socket score

Version published
Maintainers
1
Created
Source

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

Keywords

FAQs

Package last updated on 19 Mar 2020

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc