【问题标题】:Typescript complains that react component optional prop could possibly be undefined打字稿抱怨反应组件可选道具可能未定义
【发布时间】:2021-02-12 16:41:53
【问题描述】:

我有一个像这样的简单 React 组件:

interface ComponentProps {
    onClick?: () => void;
}

const Component = (props: ComponentProps) => {
    if (!props.onClick) {
        return <></>;
    }

    return (
        // Typescript complains: Cannot invoke an object which is possibly 'undefined'.ts(2722)
        <button onClick={() => props.onClick()}>  
            test
        </button>
    );
};

Typescript 抱怨 props.onClick 可能未定义,即使在检查之后也是如此。

谁能帮我理解为什么 props.onClick 可能仍然可能是未定义的?

【问题讨论】:

  • 您将onClick() 标记为可选,这意味着它可以是未定义的。尝试从您的界面中删除onClick() 之后的问号。
  • 我知道这是一个可选的,删除 ?让抱怨消失。但我的问题是为什么检查后 if (!props.onClick) return >; props.onClick 仍然可能未定义
  • 那是因为你在回调中使用它。只需&lt;button onClick={props.onClick}&gt; ...
  • 这是因为理论上在回调调用之前,一些其他代码可以更改道具并可能将undefined 分配给props.onClick。类似的问题stackoverflow.com/q/64334847/1113002 更多关于控制流分析的信息在这里github.com/microsoft/TypeScript/issues/9998
  • 如果您使用解构const Component = ({ onClick }: ComponentProps) =&gt; { ... } 语法,它应该修复它,因为当onClick 被这样解构时,您无法重新分配它。

标签: javascript reactjs typescript frontend


【解决方案1】:

这是因为您在ComponentProps 接口定义中使用了optional property operator ?

我看到了解决这个问题的两种方法:

第一个是将可选属性定义更改为强制删除?可选属性运算符,因此您无需验证onClick函数是否传递给组件。

interface ComponentProps {
   onClick: () => void;
}
const Component = ({onClick}) => (
   <button onClick={onClick}>
       test
   </button> 
)

l 第二个是创建一个处理函数来验证可选的onClick 函数。

inteface ComponentProps {
    onClick?: () => void;
}
const Component = ({onClick}: ComponentProps) => (
   <button onClick={() => {
       if(onClick) onClick();
   }}>  
       test
   </button>
)

奖金。 您可以结合使用扩展语法和三元运算符来验证传递给 React 组件的可选属性。

interface ComponentProps {
   onClick?: () => void;
}
const Component = ({onClick}: ComponentProps) => (
   <button {...(onClick ? {onClick} : {})}>test</button>
)

【讨论】:

    【解决方案2】:

    问题在于您的 props 对象是可变的,TypeScript 假定它可以在您的 !props.onClick 检查和回调执行之间进行修改。

    要解决您的问题,您可以解构props 对象并将onClick 属性用作作用域变量:

    const Component = ({onClick}: ComponentProps) => {
        if (!onClick) {
            return <></>;
        }
    
        return (
            <button onClick={() => onClick()}>  
                test
            </button>
        );
    };
    

    【讨论】:

    • 如果 props 发生突变,假设 props.onClick 更改为 undefined,那么它会触发重新渲染,对吧?如果是这样,按钮将不再呈现。我的意思是,如果 props.onClick 未定义,则没有按钮,如果 props.onClick 已定义,则有按钮。我理解正确吗?
    • @Ethan 否。如果 props 对象发生了变异,React 将不会意识到它并且不会重新渲染组件。在 React 世界中,props 对象从不发生变异。当一个组件被渲染时,它会收到一个 new props 对象。问题是 TypeScript 不知道 React 内部是如何工作的,即使从来没有这样的情况,它也假定 props 对象可以被变异。
    【解决方案3】:

    你为什么不试试

    interface ComponentProps {
        onClick?: () => void;
    }
    
    const Component = ({ onClick = () => {}}: ComponentProps) => {
    
    
        return (
          
            <button onClick={() => props.onClick()}>  
                test
            </button>
        );
    };
    

    【讨论】:

      【解决方案4】:

      使用props.onClick?.() 而不是props.onClick()

      这告诉 typescript 只有在定义时才调用 onClick()。

      Learn more about optional chaining here

      【讨论】:

        猜你喜欢
        • 2020-03-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-14
        • 2019-07-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多