为什么函数已判断变量非undefined,TypeScript仍报变量可能为undefined?
问题原因
TypeScript 的类型收窄能力仅作用于当前作用域内的逻辑,不会跨函数追踪布尔返回值对应的前置校验条件。你将非空、长度校验逻辑封装进isApproveEnabled之后,这个函数的返回值对TS来说仅为普通的boolean类型,TS不会自动推导「返回true等价于someKey1/someKey2/someKey3均为非空字符串、数组长度符合要求」这条隐含规则,因此无法在isApproveEnabled() === true的分支里自动把三个变量的类型从string | undefined收窄为string,就会触发类型不匹配的报错。
解决方案
方案1:使用自定义类型守卫(最规范)
通过类型谓词显式告诉TS,当函数返回true时,传入的props一定符合指定的非空结构,TS就能自动完成类型收窄:
// 先定义校验通过后的props结构类型 type EnabledComponentProps = SomeComponentProps & { someKey1: string; someKey2: string; someKey3: string; regions: [unknown]; // 对应长度为1的数组 attributes: [unknown]; } // 把props作为入参传入,用类型谓词声明返回值和入参类型的关联 const isApproveEnabled = (props: SomeComponentProps): props is EnabledComponentProps => { return ( !!props.someKey1 && !!props.someKey2 && !!props.someKey3 && props.regions.length === 1 && props.attributes.length === 1 ); }; // 调用时传入props const onClickApprove = () => { if (isApproveEnabled(props)) { // 此处TS会自动识别props下的三个key都是非空string callSomeFunction( props.someKey1, props.someKey2, props.someKey3 ) .then(res => { setApprovalSucceeded(true); }) .catch(error => { setApprovalSucceeded(false); }) .finally(() => setApprovalPending(false)); } }; // 按钮处的disabled判断也同步改为传入props return ( <SomeButton className="approve-button" onClick={onClickApprove} disabled={!isApproveEnabled(props)} > 批准 </SomeButton> )
方案2:返回校验通过的参数(无需写类型声明)
调整封装函数的逻辑,校验通过时直接返回需要的非空参数,校验不通过返回null,TS可以自动推导返回值的类型:
const getValidApproveParams = () => { if (someKey1 && someKey2 && someKey3 && regions.length === 1 && attributes.length === 1) { return { someKey1, someKey2, someKey3 }; } return null; } const onClickApprove = () => { const validParams = getValidApproveParams(); if (validParams) { // 此处validParams下的属性都会被TS识别为非空string callSomeFunction( validParams.someKey1, validParams.someKey2, validParams.someKey3 ) // 后续逻辑不变 } }; // 按钮disabled判断 disabled={!getValidApproveParams()}
方案3:非空断言(最简单暴力)
如果你确定isApproveEnabled()返回true时三个变量一定不可能为undefined,可以直接在变量后加!非空断言,主动告诉TS忽略undefined的可能性:
if (isApproveEnabled()) { callSomeFunction( someKey1!, someKey2!, someKey3! ) // 后续逻辑不变 }
注意该方案相当于主动绕过TS的类型检查,如果你后续修改了isApproveEnabled的校验逻辑漏了非空判断,运行时可能出现传入undefined的问题。
内容的提问来源于stack exchange,提问作者CustardBun
相关产品推荐
相关产品推荐

