微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用文字类型保护缩小 TypeScript 不相交联合在函数中有效,但不适用于 React 状态

如何解决使用文字类型保护缩小 TypeScript 不相交联合在函数中有效,但不适用于 React 状态

我有一个具有 nextAction 状态的 reducer,它作为一种回调工作。 NextAction 输入如下:

type NextActionSave = {type: 'save'};
type NextActionSaveAndSet = {type: 'saveAndSet',name: TextFieldName,value: string};
type NextAction = NextActionSave | NextActionSaveAndSet;
interface EditRowState {
  ...
  nextAction: NextAction | null;
}

在另一个文件中,我有一个关于 state.nextAction.type 的 switch 语句

import React from 'react';
import {EditRowState,EditRowAction,NextAction} from './reducer';

interface Props {
  save: () => Promise<void>;
  state: EditRowState;
  dispatch: React.dispatch<EditRowAction>;
}

const useNextAction = (props: Props) => {
  React.useEffect(() => {
    executeNextAction(props.state.nextAction);
  },[props.state.nextAction]);

  const executeNextAction = (nextAction: NextAction | null) => {
    if (nextAction === null) return;

    switch(nextAction.type) {
      case 'save':
        props.save();
        break;
      case 'saveAndSet':
        props.save().then(() => {
          const {name,value} = nextAction;
          props.dispatch({type: 'set',name,value,advance: true});
        });
      default: return;
    }
  };
};

这有效。 Here is a TypeScript Playground of the executeNextAction 显示了 executeNextAction 函数

如果我在 useEffect 中移动 executeNextAction 的主体,以便 nextAction 直接来自状态,它会显示属性 'name' 在类型 'NextAction' 上不存在”。对于 value 属性,我收到相同的错误。我没有单独的 executeNextAction 函数代码如下。 Here is a simplified version of my code below in a TypeScript Playground showing the error.

import React from 'react';
import {EditRowState,EditRowAction} from './reducer';

interface Props {
  save: () => Promise<void>;
  state: EditRowState;
  dispatch: React.dispatch<EditRowAction>;
}

const useNextAction = (props: Props) => {
  React.useEffect(() => {
    if (props.state.nextAction === null) return;

    switch(props.state.nextAction.type) {
      case 'save':
        props.save();
        break;
      case 'saveAndSet':
        props.save().then(() => {
          const {name,value} = props.state.nextAction;
          props.dispatch({type: 'set',advance: true});
        });
      default: return;
    }
  },[props.state.nextAction]);
};

如果我使用 as NextActionSaveAndSet 对 props.state.nextAction 进行类型转换,它会起作用。看起来 switch 语句充当 literal type guard,所以我不需要类型转换。我猜这就是它在我将代码移动到 executeNextAction 函数的版本中工作的原因。使用 nextAction 作为函数参数或在状态上访问它有什么区别?如果我在某处添加as const,我可以在 state 上使用它吗?

解决方法

我无法正确解释为什么会这样,但我有两种不涉及断言的不同解决方案。

  1. this.props.nextAction 保存到变量中。
const useNextAction = (props: Props) => {
  React.useEffect(() => {
    const {nextAction} = props.state;
    if (nextAction === null) return;

    switch(nextAction.type) {
      case 'save':
        props.save();
        break;
      case 'saveAndSet':
        props.save().then(() => {
          const {name,value} = nextAction;
          props.dispatch({type: 'set',name,value,advance: true});
        });
      default: return;
    }
  },[props.state.nextAction]);
};
  1. 在回调之外分解 namevalue
const useNextAction = (props: Props) => {
  React.useEffect(() => {
    if (props.state.nextAction === null) return;

    switch(props.state.nextAction.type) {
      case 'save':
        props.save();
        break;
      case 'saveAndSet':
        const {name,value} = props.state.nextAction;
        props.save().then(() => {
          props.dispatch({type: 'set',[props.state.nextAction]);
};

Typescript Playground Link

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?