Redux Reducer中的打字稿

时间:2019-08-02 19:41:07

标签: typescript redux

redux guide to typescript之后,我为减速器想到了以下代码。但是,Typescript无法在switch case语句上推断正确的类型。

通过阅读this answer及其指向的typescript docs,我能够使用接口类型变量上的字符串文字使它工作。但是我不想在其中使用文字,因为我将动作字符串导出到Actions变量中,如下面的代码所示。

要使它像redux指南那样工作,我缺少什么?

export const Action = {
  action1:'ACTION1',
  action2:'ACTION2'
}

interface actionType1 {
  type: typeof Action.action1, 
  stringPayload:string
}

interface actionType2 {
  type: typeof Action.action2,
  objectPayload:{
    str: string
  } 
}

type actionType = actionType1 | actionType2;

interface stateType {
  str:string,
}

const defaultState = {
  str:''
};


const reducer = ( state = defaultState, action:actionType) : stateType => {
  switch(action.type){
    case Action.action1:
      return {
        str:action.stringPayload //stringPayload appears as error
      }
        /*
        [ts]
        Property 'stringPayload' does not exist on type 'actionType'.
        Property 'stringPayload' does not exist on type 'actionType2'.
        */ 

    case Action.action2:
      return action.objectPayload //objectPayload appears as error
      /*
      [ts]
      Property 'objectPayload' does not exist on type 'actionType'.
      Property 'objectPayload' does not exist on type 'actionType1'
      */

    default:
      return state  
  }
}

2 个答案:

答案 0 :(得分:1)

它编译出错,因为reducer中的Action.action1Action.action2解析为字符串。如果将鼠标悬停在Action类型上,则可以看到其解释:

const Action: {
    action1: string;
    action2: string;
}

您还可以通过编写以下代码进行测试

type TestAction2Prop = typeof Action.action2 //  type TestAction2Prop = string

要解决此问题,您必须明确地告诉TypeScript,不得将Action的文字类型扩展(例如,将'ACTION1'转换为字符串)。您可以通过const assertions来做到这一点:

export const Action = {
  action1:'ACTION1',
  action2:'ACTION2'
}  as const

Playground

答案 1 :(得分:0)

尝试一下:

export class Action {
    static action1:'ACTION1';
    static action2:'ACTION2';
}

interface actionType1 {
    type: typeof Action.action1,
    stringPayload:string
}

interface actionType2 {
    type: typeof Action.action2,
    objectPayload:{
        str: string
    }
}

type actionType = actionType1 | actionType2;

interface stateType {
    str:string,
}

const defaultState = {
    str:''
};


const reducer = ( state = defaultState, action:actionType) : stateType => {
    switch(action.type){
        case Action.action1:
            return {
                str:action.stringPayload //stringPayload appears as error
            }
        /*
        [ts]
        Property 'stringPayload' does not exist on type 'actionType'.
        Property 'stringPayload' does not exist on type 'actionType2'.
        */

        case Action.action2:
            return action.objectPayload //objectPayload appears as error
        /*
        [ts]
        Property 'objectPayload' does not exist on type 'actionType'.
        Property 'objectPayload' does not exist on type 'actionType1'
        */

        default:
            return state
    }
}