reactjs - 当我的函数检查它是否未定义时,为什么打字稿会抱怨该变量可能未定义?
问题描述
我有一个功能组件,其中一部分是有条件启用的按钮。
简化:
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() ?
解决方案
TypeScript 没那么聪明。它不“知道” someKey1
etc 绝对是string
不是string | undefined
,因为它实际上并没有分析其中的语句isApproveEnabled
来缩小someKey1
//的类型someKey2
。someKey3
在调用函数的时候,TypeScript 只参考了类型窄化的返回签名;当使用 if 语句时,情况并非如此,TypeScript 必须评估整个表达式以确保类型安全。
TypeScript 确实有专门用于此的x is T
语法 - 代替 return 语句的语法。但是,它仅适用于传递给函数的值,您不能指定多个值。你可以用一个数组来欺骗它,虽然......
const isApproveEnabled = (args: (string | undefined)[]): args is string[] => {
return args.some(a => a === undefined) === false
}
没有办法做你现在想做的事,但我不觉得这是一个很大的损失,因为对我来说它也有点难以阅读 - 你的函数断言不变量是真的,谁知道以后如何修改这些不变量?
当涉及到异步代码时,这种事情将特别难以证明!
如果您真的想缩小类型,我的建议是使用正确的类型isApproveEnabled
返回经过清理的值,而不是断言不变量是正确的。
这也会更容易阅读;如果您提出的建议有效,那么在调用函数后,您必须检查函数的主体以找出类型变窄的原因,因为函数的类型签名中没有任何内容表明该变窄。