【问题标题】:Typescript reducer's switch case typeguard doesn't work with object spreadTypescript reducer switch case type guard 不适用于对象传播
【发布时间】:2022-01-22 16:23:12
【问题描述】:

我有一个 reducer,它根据 action.type 执行不同的操作,某些操作的操作负载不同。

    export enum ActionType {
      UpdateEntireState = "UPDATE_ENTIRE_STATE",
      UpdateStateItem = "UPDATE_STATE_ITEM"
    }
    
    type TypeEditData = {
      id: string;
      name: string;
      surname: string;
      age: number;
    };
    
    export type State = TypeEditData[];
    export type Action = UpdateEntireState | UpdateStateItem;
    
    type UpdateEntireState = {
      type: ActionType.UpdateEntireState;
      payload: State;
    };
    
    type UpdateStateItem = {
      type: ActionType.UpdateStateItem;
      payload: { id: string; data: TypeEditData };
    };
    
    export function reducer(state: State, action: Action): State {
      const { type, payload } = action;
    
      switch (type) {
        case ActionType.UpdateEntireState: {
          return [...payload];
        }
        case ActionType.UpdateStateItem: {
          const person = state.filter((item) => item.id === payload.id);
          return [...state, person[0]];
        }
        default: {
          throw Error("Wrong type of action!");
        }
      }
    }

此代码不起作用,错误会说我的操作负载可以是State{ id: string; data: TypeEditData }。 但是,如果我使用像这样的点符号访问 switch case 内的有效负载属性

return [...action.payload];

不会有任何错误,并且类型保护可以正常工作。 const { type, payload } = action;action.typeaction.payload 在类型方面有何不同?为什么 typeguard 不能使用扩展语法?

TS 版本 - 4.3.4

【问题讨论】:

标签: javascript typescript reduce typeguards


【解决方案1】:

问题是您在action 上没有可用类型信息之前定义了payload,因此它具有联合类型

State | {
    id: string;
    data: TypeEditData;
};

在每个 case 语句中定义一个局部变量或简单地使用action.payload,编译器就知道它的类型:

export function reducer(state: State, action: Action): State {
  // const { type, payload } = action;

  switch (action.type) {
    case ActionType.UpdateEntireState: {
      return [...action.payload];
    }
    case ActionType.UpdateStateItem: {
      const person = state.filter((item) => item.id === action.payload.id);
      return [...state, person[0]];
    }
    default: {
      throw Error("Wrong type of action!");
    }
  }
}

变量类型在声明时显式建立(例如const a: string)或在初始化时隐式建立(例如a = 4)。随后的类型保护构造不用于重新评估变量的类型。相反,由于此时已经定义了变量的类型,因此该类型用于验证后面的构造是否对变量有效。

【讨论】:

    【解决方案2】:

    Action接口默认自带type属性。

    export interface Action {
        type: string;
    }
    

    如果您可以扩展 Action 接口以将有效负载添加为对象数组,那么 typescript 不会向您抛出错误。 像这样的东西,在你的减速器函数中你可以像这样使用

    interface CustomAction extends Action{
        payload: Array<any>
    }
    
    
    export function reducer(state: State, action: CustomAction): State {
    

    【讨论】:

    • 不行,const person = state.filter((item) =&gt; item.id === payload.id),TS在payload.id上依然报错
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-27
    • 1970-01-01
    • 2021-12-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多