{"id":16715118,"url":"https://github.com/dean177/create-reducer-extra","last_synced_at":"2025-03-21T20:33:54.096Z","repository":{"id":15351269,"uuid":"77827259","full_name":"Dean177/create-reducer-extra","owner":"Dean177","description":"Create boilerplate-free, type-safe Redux reducers","archived":false,"fork":false,"pushed_at":"2022-12-07T09:46:58.000Z","size":643,"stargazers_count":5,"open_issues_count":12,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-10-09T21:35:12.577Z","etag":null,"topics":["reducer","redux","typescript","utility"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Dean177.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-01-02T10:55:23.000Z","updated_at":"2023-11-10T10:07:44.000Z","dependencies_parsed_at":"2023-01-11T19:05:15.990Z","dependency_job_id":null,"html_url":"https://github.com/Dean177/create-reducer-extra","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dean177%2Fcreate-reducer-extra","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dean177%2Fcreate-reducer-extra/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dean177%2Fcreate-reducer-extra/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dean177%2Fcreate-reducer-extra/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Dean177","download_url":"https://codeload.github.com/Dean177/create-reducer-extra/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221818958,"owners_count":16885862,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["reducer","redux","typescript","utility"],"created_at":"2024-10-12T21:08:25.551Z","updated_at":"2024-10-28T10:50:29.853Z","avatar_url":"https://github.com/Dean177.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# create-reducer-extra\n\n[![CircleCI](https://circleci.com/gh/Dean177/create-reducer-extra.svg?style=shield)](https://circleci.com/gh/Dean177/create-reducer-extra)\n[![codecov](https://codecov.io/gh/Dean177/create-reducer-extra/branch/master/graph/badge.svg)](https://codecov.io/gh/Dean177/create-reducer-extra)\n[![Npm](https://badge.fury.io/js/create-reducer-extra.svg)](https://www.npmjs.com/package/create-reducer-extra)\n\nA few helpful utilities for creating boilerplate-free [Redux](https://redux.js.org/introduction) reducers with first class support for [Typescript](https://www.typescriptlang.org/)\n\n\n## Installation\n\n`yarn add create-reducer-extra`\n\nOr using npm\n\n`npm install --save create-reducer-extra`\n\n## Usage\n\nAs a convenience all reducing functions are called directly with the actions *payload* property\n\n```js\n// actions.ts\nimport { action } from 'create-reducer-extra'\n\nexport const actionA = (someNumber) =\u003e ({ type: 'A', payload: someNumber })\nexport const actionB = (someString) =\u003e ({ type: 'B', payload: someString })\nexport const actionC = (someBool) =\u003e action('C', someBool)\n\n// reducer.ts\nimport { createReducer } from 'create-reducer-extra'\n\nconst initialState = { counter: 0 }\n\nexport const reducer = createReducer\u003cState, HandledActions\u003e(initialState, {\n  A: (state, payload) =\u003e ({ counter: state.counter + payload[0] }),\n  B: (state, payload) =\u003e ({ counter: state.counter + Number(payload) }),\n  C: (state, payload) =\u003e ({ counter: payload ? state.counter + 1 : state.counter - 1 }),\n})\n```\n\n## API\n\nNote that all of the createReducer functions:\n- Expects actions to be of the form `{ type: string, payload: any }`\n- Your your handler functions will be called directly with the *payload* of the action\n\n### `action`\n\nA tiny utility for creating actions in the format `createReducer` expects\n\n```js\n// actions.ts\nimport { action } from 'create-reducer-extra'\n\nconst changeName = (name) =\u003e action('ChangeName', { newName: name })\n\nchangeName('Fluffy') // { type: 'ChangeName', payload: { newName: 'Fluffy' } }\n```\n\n### `createMergeReducer`\n\nAllows you to only specify what has changed in your reducing function, e.g\n\n```js\nimport { createMergeReducer } from 'create-reducer-extra'\n\nconst initialState = {\n  animals: ['ant', 'bat'],\n  counter: 2,\n}\n\nconst reducer = createMergeReducer(initialState, {\n  Add: ({ counter }, incrementAmount) =\u003e ({ counter: counter + incrementAmount}),\n  NewAnimals: ({ animals }, newAnimals) =\u003e ({ animals: [...animals, ...newAnimals] }),    \n})\n\nreducer(initialState, { payload: 5, type: 'Add' })\n// { counter: 7, animals: ['ant', 'bat'] }\n\nreducer(initialState, { payload: ['cat', 'dog'], type: 'NewAnimals' })\n// { counter: 2, animals: ['ant', 'bat', 'cat', 'dog] }\n\n```\n\n### `createReducer`\n\nFor when you want to specify exactly what the next state will be\n\n\n```js\nimport { createReducer } from 'create-reducer-extra'\n\nconst initialState = {\n  animals: ['ant', 'bat'],\n  counter: 2,\n}\n\nconst reducer = createReducer(initialState, {\n  Add: ({ counter }, incrementAmount) =\u003e ({ counter: counter + incrementAmount}),\n  NewAnimals: ({ animals, counter }, newAnimals) =\u003e ({ animals: [...animals, ...newAnimals], counter }),    \n})\n\nreducer(initialState, { payload: 3, type: 'Add' })\n// { counter: 5 }\n// Note the missing 'animals' property\n\n```\n\n### `createResettableReducer`\n\nProvides the ability to *reset* a reducer to its initial state.\n\nThis can be useful for handling things such as a logout in a single page app.\n\nThe *ResetState* can be overridden in the handler to provide custom behaviour.\n\n```js\nimport { createResettableReducer, resetState } from 'create-reducer-extra'\n\nconst initialState = { animals: ['ant', 'bat'], counter: 2 }\n\nconst reducer = createResettableReducer(initialState, {\n  Add: ({ counter }, incrementAmount) =\u003e ({ counter: counter + incrementAmount}),\n  NewAnimals: ({ animals }, newAnimals) =\u003e ({ animals: [...animals, ...newAnimals] }),    \n})\n\nconst nextState = reducer(initialState, { payload: 5, type: 'Add' })\n// { counter: 7, animals: ['ant', 'bat'] }\n\nreducer(nextState, resetState())\n// { animals: ['ant', 'bat'], counter: 2 } === initialState\n```\n\n### `createResetMergeReducer`\n\nCombines the functionality of createMergeReducer and createResettableReducer.\n\nNote that if the *ResetState* action is handled by the reducer, the result returned will be merged into the *current* state e.g.\n\n```js\nimport { createResetMergeReducer, resetState } from 'create-reducer-extra'\n\nconst initialState = { animals: ['ant', 'bat'], counter: 2 }\n\nconst reducer = createResetMergeReducer(initialState, {\n  Add: ({ counter }, incrementAmount) =\u003e ({ counter: counter + incrementAmount}),\n  [ResetState]: ({ animals }) =\u003e ({ animals: [] }),    \n})\n\nconst nextState = reducer(initialState, resetState())\n// { counter: 2, animals: [] }\n```\n\n## Usage with Typescript\n\nThis library leverages some new features introduced in Typescript 2.8 to provide complete type safety with minimal boilerplate. To take advantage of completely type-safe reducers you need to:\n\n1. Define your action creators\n\n  ```typescript\n  // actions.ts\n  import { action, Action } from 'create-reducer-extra'\n\n  const actionA = (param: Array\u003cnumber\u003e): Action\u003c'A', Array\u003cnumber\u003e\u003e =\u003e\n    ({ type: 'A', payload: param })\n\n  const actionB = (param: string): Action\u003c'B', string\u003e =\u003e ({ type: 'B', payload: param })\n\n  const actionC = () =\u003e action('C', false)\n  ```\n\n2. In your reducer create:\n  - A type to represent the state of the reducer\n  - A type to represent the actions your reducer should handled\n\n3. Provide those as type parameters to your reducer-creator of choice:\n\n  ```typescript\n  // reducer.ts\n  import { createReducer } from 'create-reducer-extra'\n  import * as actions from './actions'\n\n  type State = { counter: number }\n  type HandledActions = typeof actions\n\n  const reducer = createReducer\u003cState, HandledActions\u003e(initialState, {\n    A: (state, payload) =\u003e ({ counter: state.counter + payload[0] }),\n    B: (state, payload) =\u003e ({ counter: state.counter + Number(payload) }),\n    C: (state, payload) =\u003e ({ counter: payload ? state.counter + 1 : state.counter - 1 }),\n  })\n  ```\n\nVoila, everything is type-safe!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdean177%2Fcreate-reducer-extra","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdean177%2Fcreate-reducer-extra","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdean177%2Fcreate-reducer-extra/lists"}