{"id":26906020,"url":"https://github.com/drmats/red-g","last_synced_at":"2026-04-11T11:40:06.346Z","repository":{"id":57349480,"uuid":"415222990","full_name":"drmats/red-g","owner":"drmats","description":"Statically typed actions and reducers for redux. ","archived":false,"fork":false,"pushed_at":"2024-03-01T15:42:17.000Z","size":1472,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-09-23T01:54:05.802Z","etag":null,"topics":["actions","javascript","reducers","redux","typescript"],"latest_commit_sha":null,"homepage":"https://drmats.github.io/red-g/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/drmats.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,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2021-10-09T06:27:08.000Z","updated_at":"2024-01-29T14:59:58.000Z","dependencies_parsed_at":"2024-03-01T16:51:03.807Z","dependency_job_id":null,"html_url":"https://github.com/drmats/red-g","commit_stats":{"total_commits":618,"total_committers":2,"mean_commits":309.0,"dds":"0.0016181229773463146","last_synced_commit":"9ac11860f7fdf1b52634001707be00703cd0adf9"},"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drmats%2Fred-g","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drmats%2Fred-g/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drmats%2Fred-g/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drmats%2Fred-g/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/drmats","download_url":"https://codeload.github.com/drmats/red-g/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246628213,"owners_count":20808106,"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":["actions","javascript","reducers","redux","typescript"],"created_at":"2025-04-01T10:59:38.184Z","updated_at":"2026-04-11T11:40:01.299Z","avatar_url":"https://github.com/drmats.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# red-g\n\nStatically typed actions and reducers for **[redux](https://redux.js.org/)**.\n\n[![npm version](https://img.shields.io/npm/v/red-g.svg)](https://www.npmjs.com/package/red-g)\n[![GitHub code size](https://img.shields.io/github/languages/code-size/drmats/red-g.svg)](https://github.com/drmats/red-g)\n[![GitHub tag](https://img.shields.io/github/tag/drmats/red-g.svg)](https://github.com/drmats/red-g)\n[![npm license](https://img.shields.io/npm/l/red-g.svg)](https://www.npmjs.com/package/red-g)\n\n```bash\n$ npm i red-g\n```\n\n\u003cbr /\u003e\n\n\n\n\n## ok, what's in here and how to use it?\n\n1. actions as non-const enums (example `app/action_type.ts` file):\n    ```typescript\n    export enum AppActionType {\n        RESET = \"App/RESET\",\n        READY = \"App/READY\",\n        NOT_READY = \"App/NOT_READY\",\n        DELAYED = \"App/DELAYED\",\n        CLEAR_ERROR = \"App/CLEAR_ERROR\",\n    }\n    ```\n\n2. easy action creators - define only those carrying some payload, empty\n    ones are defined automatically (example `app/action.ts` file):\n    ```typescript\n    import { actionCreators } from \"red-g\";\n    import { AppActionType } from \"./action_type\";\n\n    export default actionCreators(AppActionType, {\n        READY: (error?: string) =\u003e ({ error }),\n        DELAYED: (condition: boolean) =\u003e ({ condition }),\n    });\n    ```\n\n3. slice of state (`app/state.ts`):\n    ```typescript\n    export default {\n        // usual stuff\n        ready: false,\n        delayed: false,\n\n        // last application error - example use\n        // of \"type predicate\" matcher\n        // (matching actions by payload content)\n        error: null as string | null,\n\n        // how many actions of this type\n        // has been spawned? - somewhat artificial\n        // example of \"boolean\" matcher usage\n        // (matching actions using string\n        // operations on their type)\n        actionCount: 0,\n    };\n    ```\n\n4. fantastic slice reducers (example `app/reducer.ts` file) with matchers:\n    ```typescript\n    import type { Action } from \"red-g\";\n    import {\n        isWithPayload,\n        sliceReducer,\n    } from \"red-g\";\n    import initState from \"./state\";\n    import app from \"./action\";\n\n    export default sliceReducer(initState) (\n        (slice) =\u003e slice\n            .handle(app.RESET, () =\u003e initState)\n\n            // this action can carry `error` payload\n            // but we're not interested in it (for now)\n            .handle(app.READY, (state) =\u003e ({\n                ...state, ready: true,\n            })\n\n            // this action is not carrying any payload\n            // and was automatically defined by\n            // call to `actionCreators()`\n            .handle(app.NOT_READY, (state) =\u003e ({\n                ...state, ready: false,\n            })\n\n            // this action is carrying simple payload and we can\n            // destructure it immediately\n            .handle(app.DELAYED, (state, { condition }) =\u003e ({\n                ...state, delayed: condition,\n            })\n\n            // same situation as with `app.NOT_READY`\n            // (shown here for completness of the example)\n            .handle(app.CLEAR_ERROR, (state) =\u003e ({\n                ...state, error: null,\n            })\n\n            // match all actions that carry payload with\n            // `error` key (\"type predicate\" matcher)\n            .match(\n                (action): action is Action\u003c{ error: string }\u003e =\u003e\n                    isWithPayload(action) \u0026\u0026 action.payload.error,\n                (state, { error }) =\u003e ({\n                    ...state, error,\n                }),\n            )\n\n            // match all actions whose `type` field starts with\n            // `App/` prefix (\"boolean\" matcher)\n            .match(\n                (action) =\u003e action.type.startsWith(\"App/\"),\n                (state) =\u003e ({\n                    ...state, actionCount: state.actionCount + 1,\n                }),\n            ),\n    );\n    ```\n\n5. now, you can combine all of your slice reducers (and actions and thunks...)\n    into nice trees (as you do usually) - example `state_logic.ts` file:\n    ```typescript\n    import appAction from \"./app/action\";\n    import appReducer from \"./app/reducer\";\n\n    export const action = {\n        app: appAction,\n        // ... and others\n    };\n\n    export const reducer = {\n        app: appReducer,\n        // ... and others\n    };\n    ```\n\n6. slice reducers are compatible with regular redux flow:\n    ```typescript\n    import {\n        createStore,\n        combineReducers,\n    } from \"redux\";\n    import {\n        bindActionCreatorsTree,\n    } from \"red-g\";\n    import {\n        action,\n        reducer,\n    } from \"./state_logic\";\n\n    const rootReducer = combineReducers(reducer);\n\n    // redux store creation\n    const store = createStore(\n        rootReducer,\n        // ... and other usual stuff\n    );\n\n    // bound actions tree\n    const act = bindActionCreatorsTree(\n        action, store.dispatch,\n    );\n    ```\n\n\nThere's more to be happy about if you use\n[IntelliSense](https://code.visualstudio.com/docs/editor/intellisense).\n\n\u003cbr /\u003e\n\n\n\n\n## can I use [immer](https://immerjs.github.io/immer/)?\n\nSure! [Curried producers](https://immerjs.github.io/immer/curried-produce)\nare supported out of the box:\n\n```typescript\nimport type { Action } from \"red-g\";\nimport {\n    isWithPayload,\n    sliceReducer,\n} from \"red-g\";\nimport produce from \"immer\";\nimport initState from \"./state\";\nimport app from \"./action\";\n\nexport default sliceReducer(initState) (\n    (slice) =\u003e slice\n        .handle(app.RESET, () =\u003e initState)\n\n        .handle(app.READY, produce((draft) =\u003e {\n            draft.ready = true;\n        })\n\n        .handle(app.DELAYED, produce((draft, { condition }) =\u003e {\n            draft.delayed = condition;\n        })\n\n        .match(\n            (action): action is Action\u003c{ error: string }\u003e =\u003e\n                isWithPayload(action) \u0026\u0026 action.payload.error,\n            produce((draft, payload) =\u003e {\n                draft.error = payload.error;\n            }),\n        ),\n);\n```\n\n\u003cbr /\u003e\n\n\n\n\n## documentation\n\n\u003e [API Reference](https://drmats.github.io/red-g/)\n\n\u003cbr /\u003e\n\n\n\n\n## namespace\n\n### **static** redux\n\n```javascript\nredux\n```\n\n\u003e ```javascript\n\u003e { actionCreators: [Function: actionCreators],\n\u003e   bindActionCreator: [Function: bindActionCreator],\n\u003e   bindActionCreators: [Function: bindActionCreators],\n\u003e   bindActionCreatorsTree: [Function: bindActionCreatorsTree],\n\u003e   createReducer: [Function: createReducer],\n\u003e   defineActionCreator: [Function: defineActionCreator],\n\u003e   emptyActionCreators: [Function: emptyActionCreators],\n\u003e   isWithPayload: [Function: isWithPayload],\n\u003e   isWithTypeField: [Function: isWithTypeField],\n\u003e   payloadActionCreators: [Function: payloadActionCreators],\n\u003e   sliceReducer: [Function: sliceReducer] }\n\u003e ```\n\n\u003cbr /\u003e\n\n\n\n\n## notes\n\nGo ahead and [file an issue](https://github.com/drmats/red-g/issues/new)\nor [submit a fresh PR](https://github.com/drmats/red-g/pulls)\nif you found a bug 🐞.\n\n\u003c/br\u003e\n\n\n\n\n## support\n\nYou can support this project via [stellar][stellar] network:\n\n* Payment address: [xcmats*keybase.io][xcmatspayment]\n* Stellar account ID: [`GBYUN4PMACWBJ2CXVX2KID3WQOONPKZX2UL4J6ODMIRFCYOB3Z3C44UZ`][addressproof]\n\n\u003cbr /\u003e\n\n\n\n\n## license\n\n**red-g** is released under the Apache License, Version 2.0. See the\n[LICENSE](https://github.com/drmats/red-g/blob/master/LICENSE)\nfor more details.\n\n\n\n\n[stellar]: https://learn.stellar.org\n[xcmatspayment]: https://keybase.io/xcmats\n[addressproof]: https://keybase.io/xcmats/sigchain#d0999a36b501c4818c15cf813f5a53da5bfe437875d92262be8d285bbb67614e22\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdrmats%2Fred-g","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdrmats%2Fred-g","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdrmats%2Fred-g/lists"}