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

immer-reducer

Package Overview
Dependencies
Maintainers
1
Versions
28
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

immer-reducer - npm Package Compare versions

Comparing version 0.2.1 to 0.3.0

1

lib/immer-reducer.d.ts

@@ -58,2 +58,3 @@ import { Draft } from "immer";

export declare function createReducerFunction<T extends ImmerReducerClass>(immerReducerClass: T, initialState?: ImmerReducerState<T>): ImmerReducerFunction<T>;
export declare function setPrefix(prefix: string): void;
/**

@@ -60,0 +61,0 @@ * INTERNAL! This is only for tests!

17

lib/immer-reducer.js

@@ -7,3 +7,3 @@ "use strict";

var immer_1 = __importDefault(require("immer"));
var PREFIX = "IMMER_REDUCER";
var actionTypePrefix = "IMMER_REDUCER";
/** The actual ImmerReducer class */

@@ -73,3 +73,3 @@ var ImmerReducer = /** @class */ (function () {

}
var type = PREFIX + ":" + getReducerName(immerReducerClass) + "#" + key;
var type = actionTypePrefix + ":" + getReducerName(immerReducerClass) + "#" + key;
var actionCreator = function () {

@@ -100,3 +100,3 @@ var args = [];

}
if (!action.type.startsWith(PREFIX + ":")) {
if (!action.type.startsWith(actionTypePrefix + ":")) {
return state;

@@ -119,12 +119,9 @@ }

});
// XXX Since Immer 1.10.3 the produce function returns immutable version
// of the object passed to it which is not ok for reducers since
// reducers should always return the same type. So we must cast the
// return value to any to avoid type errors. There is no changes from
// this to the end users because this function return value is
// explicitly typed in the parent function signature. Also there's no
// changes in the runtime behaviour.
};
}
exports.createReducerFunction = createReducerFunction;
function setPrefix(prefix) {
actionTypePrefix = prefix;
}
exports.setPrefix = setPrefix;
/**

@@ -131,0 +128,0 @@ * INTERNAL! This is only for tests!

{
"name": "immer-reducer",
"version": "0.2.1",
"version": "0.3.0",
"description": "",

@@ -40,4 +40,4 @@ "main": "lib/immer-reducer.js",

"dependencies": {
"immer": "^1.10.4"
"immer": "^1.10.5"
}
}
# immer-reducer
Create Redux reducers using [Immer](https://github.com/mweststrate/immer)!
Create terse Type-Safe Redux reducers using [Immer](https://github.com/mweststrate/immer) and Typescript!
Typescript [friendly](#100-type-safety-with-typescript) too.
Read an introductory [blog post here](https://medium.com/@esamatti/type-safe-boilerplate-free-redux-906844ec6325).

@@ -13,27 +11,55 @@

## Usage
## Motivation
Reducers are defined by extending from the `ImmerReducer` class
Turn this 💩
```js
import {ImmerReducer} from "immer-reducer";
```ts
interface SetFirstNameAction {
type: "SET_FIRST_NAME";
firstName: string;
}
// The class represents the classic switch-case reducer
class MyImmerReducer extends ImmerReducer {
interface SetLastNameAction {
type: "SET_LAST_NAME";
lastName: string;
}
// each method becomes an Action Creator
setFirstName(firstName) {
// State updates are simple as assigning a value to
// the draftState property thanks to Immer
this.draftState.firstName = firstName;
type Action = SetFirstNameAction | SetLastNameAction;
function reducer(action: Action, state: State): State {
switch (action.type) {
case "SET_FIRST_NAME":
return {
...state,
user: {
...state.user,
firstName: action.firstName,
},
};
case "SET_LAST_NAME":
return {
...state,
user: {
...state.user,
lastName: action.lastName,
},
};
default:
return state;
}
}
```
setLastName(lastName) {
this.draftState.lastName = lastName;
into this! 🚀
```ts
import {ImmerReducer} from "immer-reducer";
class MyImmerReducer extends ImmerReducer<State> {
setFirstName(firstName: string) {
this.draftState.user.firstName = firstName;
}
// You can combine methods to a single Action Creator
setName(firstName, lastName) {
this.setFirstName(firstName);
this.setLastName(lastName);
setLastName(lastName: string) {
this.draftState.user.lastName = lastName;
}

@@ -43,5 +69,11 @@ }

Generate Action Creators and the actual reducer function for Redux
**Without losing the type-safety!** 🔥
```js
Oh, and you get the action creators for free! 🤗 🎂
## Usage
Generate Action Creators and the actual reducer function for Redux from the class with
```ts
import {createActionCreators, createReducerFunction} from "immer-reducer";

@@ -55,8 +87,10 @@

```js
```ts
import {createStore} from "redux";
const initialState = {
firstName: "",
lastName: "",
user: {
firstName: "",
lastName: "",
},
};

@@ -69,10 +103,46 @@

```js
```ts
store.dispatch(ActionCreators.setFirstName("Charlie"));
store.dispatch(ActionCreators.setLastName("Brown"));
expect(store.getState().firstName).toEqual("Charlie");
expect(store.getState().lastName).toEqual("Brown");
expect(store.getState().user.firstName).toEqual("Charlie");
expect(store.getState().user.lastName).toEqual("Brown");
```
## Typed Action Creators!
This library by no means requires you to use Typescript but it was written
specifically Typescript usage in mind because I was unable to find any other
libraries that make Redux usage both terse and 100% type safe.
The generated `ActionsTypes` object respect the types used in the class
```ts
const action = ActionCreators.setFirstName("Charlie"); // OK
action.payload[0]; // OK string type
action.payload[1]; // Type error. Only one argument.
ActionCreators.setFirstName(1); // Type error. Needs string.
ActionCreators.setWAT("Charlie"); // Type error. Unknown method
```
The reducer function is also typed properly
```ts
const reducer = createReducerFunction(MyImmerReducer);
const initialState: State = {
user: {
firstName: "",
lastName: "",
},
};
reducer(initialState, ActionCreators.setFirstName("Charlie")); // OK
reducer(initialState, {type: "WAT"}); // Type error
reducer({wat: "bad state"}, ActionCreators.setFirstName("Charlie")); // Type error
```
## How
Under the hood the class is deconstructed to following actions:

@@ -101,3 +171,3 @@

# Integrating with the Redux ecosystem
## Integrating with the Redux ecosystem

@@ -122,3 +192,3 @@ To integrate for example with the side effects libraries such as

// action.payload - recognized as string
map(action => action.payload.toUpperCase()),
map(action => action.payload[0].toUpperCase()),
...

@@ -128,58 +198,2 @@ );

# 100% Type Safety with Typescript
This library by no means requires you to use Typescript but it was written
specifically Typescript usage in mind because I was unable to find any other
libraries that make Redux usage both boilerplate free and 100% type safe.
Pretty advanced Typescript sorcery was required and so this library requires
Typescript 3.1 or later. But the end results is really simple for the end user.
The Typescript usage does not differ that much from the Javascript usage.
Just pass your state type as the type argument for the class
```ts
interface State {
// The state can be defined as read only
readonly firstName: string;
readonly lastName: string;
}
class MyImmerReducer extends ImmerReducer<State> {
setFirstName(firstName: string) {
// draftState has the State type but the readonly
// flags are removed here to allow type safe mutation
this.draftState.firstName = firstName;
}
setLastName(lastName: string) {
this.draftState.lastName = lastName;
}
}
```
The generated `ActionsTypes` object now respects the types used in the class
```ts
const ActionCreators = createActionCreators(MyImmerReducer);
ActionCreators.setFirstName("Charlie"); // OK
ActionCreators.setFirstName(1); // Type error
ActionCreators.setWAT("Charlie"); // Type error
```
The reducer function is also typed properly
```ts
const reducer = createReducerFunction(MyImmerReducer);
const initialState: State = {
firstName: "",
lastName: "",
};
reducer(initialState, ActionCreators.setFirstName("Charlie")); // OK
reducer(initialState, {type: "WAT"}); // Type error
reducer({wat: "bad state"}, ActionCreators.setFirstName("Charlie")); // Type error
```
## Examples

@@ -190,1 +204,8 @@

<https://github.com/epeli/typescript-redux-todoapp>
## API
- `createReducerFunction(klass: ImmerReducer: initialState?: Object)`
- `createActionCreators(klass: ImmerReducer)`
- `setPrefix(prefix: string)`
- The default prefix in actions is is `IMMER_REDUCER`. Call this customize it for you app.

Sorry, the diff of this file is not supported yet

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