将immer用于Redux的reducer时出现打字稿错误

时间:2020-01-01 15:15:55

标签: typescript redux immer.js

我正在尝试在Typescript项目中将Immer与Redux一起使用。

Redux减速器可以键入为:

Reducer<State, Action>

我应该能够使用Immer's produce function创建一个等效的reducer,这使我们能够对草稿副本进行变异。但是类型不匹配。错误:“无法将Undefined分配给...”这可能与redux在开始时将undefined作为状态参数传递有关。如果减速器不匹配Reducer<State, Action>,则无法将其传递给createStore

打字稿版本3.5.3。

我该如何优雅地解决这个问题? enter image description here

5 个答案:

答案 0 :(得分:1)

我还没有找到一种使之工作的方法,目前我从减速机中退回农产品

avarage: 4

答案 1 :(得分:1)

通常,produce 返回状态,因此我们不需要返回任何内容。然而,这会导致 typescript 出错,因为如果 reducer 中的任何 case 没有返回任何内容,typescript 将对其进行评估,您的 reducer 的返回值类型之一可能是 undefined

解决方案是在每个案例的末尾,您明确返回状态:

return state,

答案 2 :(得分:0)

使用produce函数的咖喱形式(将函数作为第一个参数传递)时,可以为默认值传递第二个参数。当Redux在初始化时使用未定义的值调用reducer时,可以解决类型不匹配的问题。

const initState = {
    text: "hello"
}

type State = {
    text: string
} 
type Action = {
    type: "newUrl"
    text: string 
}

const reducer: Reducer<State, Action> = produce( 
    (draftSt: Draft<State>, action: Action) => {
        switch(action.type){
            case "newUrl": 
                draftSt.text = action.text
                break 
        }
    }, 
    initState
)

然后可以将减速器安全地传递到createStoreconfigureStore

答案 3 :(得分:0)

我遇到了同样的问题,但我记得官方zip拥有一个createReducer助手,该助手在内部使用Immer。查看他们的代码可以提示他们如何解决此问题。

import createNextState, { Draft } from 'immer'

export function createReducer<S>(
  initialState: S,
  ...): Reducer<S> {
  ...

  return function(state = initialState, action): S {
    // @ts-ignore createNextState() produces an Immutable<Draft<S>> rather
    // than an Immutable<S>, and TypeScript cannot find out how to reconcile
    // these two types.
    return createNextState(state, (draft: Draft<S>) => {
      const caseReducer = actionsMap[action.type]
      return caseReducer ? caseReducer(draft, action) : undefined
    })
  }
}

(请参见Redux Toolkit。为简洁起见,我用“ ...”缩短了不相关的部分)。

您可以在这里看到他们的辅助函数返回一个结构正常的化合器,其主要工作是将state传递给createNextDraft函数。有趣的是,这只是从Immer导入default,因此它只是produce函数的别名。

有关如何使用此功能的示例,请参见下文:

import produce, { Draft } from 'immer';

const reducer: Reducer<State, AnyAction> = (state: State = initialState, action: AnyAction) => {
   return produce(state, (draft: Draft<State>) => {
      switch (action.type) {
        case 'Execute':
          draft.isFetching = true;
          break;
        case 'Success':
          draft.isFetching = false;
          break;
        case 'Failure':
          draft.isFetching = false;
          break;
      }
    });

答案 4 :(得分:0)

这对我有用:

 import produce from 'immer';

const reducer = (state = initialState, action: AnyAction) : State  => {
   return produce(state, (draft) => {
      switch (action.type) {
        case 'Execute':
          draft.isFetching = true;
          break;
        case 'Success':
          draft.isFetching = false;
          break;
        case 'Failure':
          draft.isFetching = false;
          break;
        default:
          draft;
      }
    });

export default reducer;