question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

createReducer does not infer action types

See original GitHub issue

When I create a reducer, the action type does not get inferred from the action. Example:

const myAction = createAction<boolean>('my/action')
const reducer = createReducer(false, {
   // action is of type "any" (and then so is the payload)
  [myAction.type](state, action) {
    return action.payload
  },
})

I am currently rolling my own setup, where I’ve got this type of inference working. Though I’m using the payload rather than the whole action object as a parameter for my callbacks.

In my case, I have to type the action like this through an extra function invocation, though I’m not sure how necessary this is.

const action = createAction('my/action')<boolean>()

I don’t pretend to understand how all of this works, but maybe someone can figure out a way to get the best of both worlds? What follows is pretty much my whole setup for this.

import { produce, Draft } from 'immer'
import { EmptyAction, PayloadAction,  createAction as createTypesafeAction } } from 'typesafe-actions'

export default function createAction<T extends string>(type: T) {
  return function<P extends any = undefined>() {
    return Object.assign(createTypesafeAction(type)<P>(), { type })
  }
}

export type Action<T extends string = string, P = never> = EmptyAction<T> | PayloadAction<T, P>

export type Producer<S, A extends Action> = A extends PayloadAction<any, infer P>
  ? (draft: Draft<S>, payload: P) => void | S
  : (draft: Draft<S>) => void | S

export type Producers<S, A extends Action> = A extends PayloadAction<any, any>
  ? { [T in A['type']]: Producer<S, A> }
  : { [T in A['type']]: Producer<S, A> }

export default function createReducer<S, A extends Action>(defaultState: S, producers: Producers<S, A>) {
  return function reducer(state = defaultState, action: A) {
    return produce(state, draft => {
      if (action.type in producers) {
          return producers[action.type](draft, action.payload)
      }
    })
  }
}

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:1
  • Comments:17 (5 by maintainers)

github_iconTop GitHub Comments

4reactions
eddywcommented, Nov 20, 2019

@Glinkis you could do this:

const increment = createAction('counter/increment', (n: number) => ({ payload: n }))
const decrement = createAction('counter/decrement', (n: number) => ({ payload: { n } }))

const counterReducer = createReducer(0, {
  [increment.type]: (state, action: ReturnType<typeof increment>) => state + action.payload,
  [decrement.type]: (state, action: ReturnType<typeof decrement>) => state - action.payload.n,
})
1reaction
Glinkiscommented, Nov 21, 2019

Given the weirdness of JS’s switch statement, can you actually do that as a switch? Something like this:

You can, but it might be a bit too clever. If/else ishould be more idiomatic in that case.

Read more comments on GitHub >

github_iconTop Results From Across the Web

createReducer - Redux Toolkit
A utility that simplifies creating Redux reducer functions. It uses Immer internally to drastically simplify immutable update logic by writing ...
Read more >
angular - @ngrx/reducer: createReducer(), and on() are not ...
I upgraded the app to Angular 8 , and using ngrx 8.3.0 as well. Now it seems like the type safety is not...
Read more >
Do not create union types with Redux Action Types. It's most ...
So, there is a long-standing TypeScript & Redux pattern of creating a union RootAction type that contains all your application's action types.
Read more >
View Raw - UNPKG
createAction) that can be used to determine the action type. ... @example ```ts import { createReducer } from '@reduxjs/toolkit' const initialState ...
Read more >
NgRx creator functions 101 - Tim Deschryver
This is not just an action creator function, but it also has a type ... the incoming action's type, TypeScript can infer the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found