ts-action
What is it?
ts-action
is a package for declaring Redux action creators with less TypeScript cruft.
Why might you need it?
I wanted a mechanism for declaring and consuming actions that involved writing as little boilerplate as possible. If you, too, want less cruft, you might find this package useful.
Also, if you are using NgRx or redux-observable, you might find the ts-action-operators
package useful, too.
For an in-depth look at TypeScript, Redux and ts-action
, have a look at: How to Reduce Action Boilerplate.
Install
Install the package using npm:
npm install ts-action --save-dev
TypeScript version 2.6 or later is required.
Usage
Action creators are declared using the action
method:
;;
Actions are created using the action creator as a class:
store.dispatchnew Foo;
Although the actions are created as class instances, internally, the prototype
is reset, so they are compatible with reactjs/redux
, as they are considered to be plain objects.
For actions with payloads, the payload type is specified using the payload
method:
;;
and the payload value is specified when creating the action:
store.dispatchnew Foo;
To have the properties added to the action itself - rather than a payload
property - use the props
method instead. Or, for more control over the parameters accepted by the constructor, use the base
method.
Action creators have a type
property that can be used to narrow an action's TypeScript type in a reducer.
The action types can be combined into a discriminated union and the action can be narrowed to a specific TypeScript type using a switch
statement, like this:
; ;;; ;
Or, the package's isType
method can be used to narrow the action's type using if
statements, like this:
; ;; ;
Or, the package's reducer
method can be used to create a reducer function, like this:
; ;; ; ;
API
action
The action
method returns an action creator. Action creators are classes and actions are be created using new
:
;;console.logfoo; // { type: "FOO" }
The type
argument passed to action
must be a string literal or have a string-literal type. Otherwise, TypeScript will not be able to narrow actions in a discriminated union.
The type
option passed to the action
method can be obtained using the creator's static type
property:
switch action.type {case Foo.type: return;default: return state;}
To define propeties, the action
method can be passed options. The options should be created using the empty
, payload
, props
or base
methods.
empty
The empty
method constructs options for the action
method. To declare an action without a payload or properties , call it like this:
;;console.logfoo; // { type: "FOO" }
Actions default to being empty; if only a type
is passed to the action
call, an empty action is created by default:
;;console.logfoo; // { type: "FOO" }
payload
The payload
method constructs options for the action
method. To declare action properties within a payload
property, call it like this:
;;console.logfoo; // { type: "FOO", payload: { name: "alice" } }
props
The props
method constructs options for the action
method. To declare action properties at the same level as the type
property, call it like this:
;;console.logfoo; // { type: "FOO", name: "alice" }
The props
method is similar to the payload
method, but with props
, the specified properties are added to the action itself - rather than a payload
property.
base
The base
method constructs options for the action
method. To declare a base class with properties, call it like this:
;;console.logfoo; // { type: "FOO", name: "alice" }
The base
method offers more control over property defaults, etc. as the base class is declared inline.
union
The union
method can be used to infer a union of actions - for type narrowing using a discriminated union. It's passed two or more action creators and returns a value that can be used with TypeScript's typeof
operator, like this:
;
isType
isType
is a TypeScript type guard that will return either true
or false
depending upon whether the passed action is of the appropriate type. TypeScript will narrow the type when used with an if
statement.
For example:
if isTypeaction, Foo
guard
guard
is a higher-order equivalent of isType
. That is, it returns a TypeScript type guard that will, in turn, return either true
or false
depending upon whether the passed action is of the appropriate type. The guard
method is useful when dealing with APIs that accept type guards.
For example, Array.prototype.filter
accepts a type guard:
;; // Inferred to be: const filtered: Foo[]
reducer
;
The reducer
method creates a reducer function out of the combined, action-specific reducers specified in the array.
on
;
The on
method creates a reducer for a specific, narrowed action and returns an object - containing the created reducer and the action's type - that can be passed to the reducer
method.