首页 > 解决方案 > 当我的函数检查它是否未定义时,为什么打字稿会抱怨该变量可能未定义?

问题描述

我有一个功能组件,其中一部分是有条件启用的按钮。

简化:

const SomeComponent = ({<lots of props>}: SomeComponentProps) => {
  const isApproveEnabled = (): boolean => {
    return (
      !!someKey1 && // someKey<N> are values from props and are all string | undefined
      !!someKey2 &&
      !!someKey3 &&
      regions.length === 1 &&
      attributes.length === 1
    );
  };

  const onClickApprove = () => {
    if (isApproveEnabled()) {
      callSomeFunction(
        someKey1,
        someKey2,
        someKey3
      )
      .then(res => {
        setApprovalSucceeded(true);
      })
      .catch(error => {
        setApprovalSucceeded(false);
      })
      .finally(() => setApprovalPending(false));
    }
  };

  return (
     <SomeButton
        className="approve-button"
        onClick={onClickApprove}
        disabled={!isApproveEnabled()}
     >
        Approve
     </SomeButton>
  )
}

问题是如果我使用 isApproveEnabled(),我会收到 Typescript 错误TS2345: Argument of type 'string | undefined' is not assignable to parameter of type 'string'.   Type 'undefined' is not assignable to type 'string'.

但是,如果我将 isApprovedEnabled() 更改为显式检查:

if (someKey1 && someKey2 && someKey3) {
   callSomeFunction(...)
}

它会起作用的。但是,我宁愿不这样做,因为实际上,我们只想使用与 isApproveEnabled() 相同的标准。

知道为什么打字稿没有收到我已经确认这些值不是未定义的吗?(我也将 isApproveEnabled 更改为仅使用 someKey1 && someKey2 && someKey3 而不是使用 !! 进行强制布尔转换,但这没有任何区别)

如何在没有 TypeScript 抱怨的情况下在这里使用 isApproveEnabled() ?

标签: reactjstypescript

解决方案


TypeScript 没那么聪明。它不“知道” someKey1etc 绝对是string不是string | undefined,因为它实际上并没有分析其中的语句isApproveEnabled来缩小someKey1//的类型someKey2someKey3在调用函数的时候,TypeScript 只参考了类型窄化的返回签名;当使用 if 语句时,情况并非如此,TypeScript 必须评估整个表达式以确保类型安全。

TypeScript 确实有专门用于此的x is T语法 - 代替 return 语句的语法。但是,它仅适用于传递给函数的值,您不能指定多个值。你可以用一个数组来欺骗它,虽然......

const isApproveEnabled = (args: (string | undefined)[]): args is string[] => {
  return args.some(a => a  === undefined) === false
}

没有办法做你现在想做的事,但我不觉得这是一个很大的损失,因为对我来说它也有点难以阅读 - 你的函数断言不变量是真的,谁知道以后如何修改这些不变量?

当涉及到异步代码时,这种事情将特别难以证明!

如果您真的想缩小类型,我的建议是使用正确的类型isApproveEnabled 返回经过清理的值,而不是断言不变量是正确的。

这也会更容易阅读;如果您提出的建议有效,那么在调用函数后,您必须检查函数的主体以找出类型变窄的原因,因为函数的类型签名中没有任何内容表明该变窄。


推荐阅读