抽离属性检查至函数后,TypeScript无法正确推断属性存在性
问题描述
我为React组件定义了如下联合类型ComponentProps:
type ComponentProps = | { standalone: true; } | { standalone: false; inContextOf: Nullable<Person | Product>; fieldSetter: Function; };
原本将属性检查逻辑内联时,TypeScript能正确推断后续代码中props.inContextOf的存在性;但把检查逻辑抽离到CheckAbortScenarios函数后,TypeScript抛出错误:
TS2339: Property inContextOf does not exist on type MapProps Property inContextOf does not exist on type { standalone: true; }
完整复现代码如下:
import { FC, useState, useEffect } from 'react'; type Person = { Name: string; Age: number; Kind: number; }; type Product = { Title: string; Description: string; Kind: number; }; type ComponentProps = | { standalone: true; } | { standalone: false; inContextOf: Nullable<Person | Product>; fieldSetter: Function; }; export const MyTestComponent: FC<ComponentProps> = (props) => { useEffect(() => { Initialize(); }, []); const CheckAbortScenarios = (): boolean => { if ( props.standalone || (!props.standalone && !props.inContextOf) || (props.inContextOf && !IsEntityPerson(props.inContextOf)) ) return true; if (props.inContextOf?.Kind == 0.0) return true; return false; }; function IsEntityPerson(entity: Person | Product): entity is Person { return (entity as Person).Name !== undefined; } const Initialize = (): void => { if (CheckAbortScenarios()) return; /*错误发生位置*/ const kind = props.inContextOf!.Kind; }; return <div></div>; };
原因分析
TypeScript的类型窄化是靠当前作用域内的代码流分析实现的,它只能跟踪同一函数里的条件判断对变量类型的影响。当你把检查逻辑抽成独立的CheckAbortScenarios函数后,TypeScript没法把函数内部的判断逻辑和外部props的类型绑定起来——这个函数只返回布尔值,TS完全不知道返回false时,props必然满足哪些类型条件,自然没法帮你窄化外部props的类型。
解决方案
要让TypeScript识别函数对props类型的窄化作用,需要使用类型谓词(Type Predicate),让函数返回值不仅是布尔值,还能明确告诉TS当返回false时props的具体类型。
修改CheckAbortScenarios的返回类型,明确标注返回false时props的类型:
const CheckAbortScenarios = (): props is Exclude<ComponentProps, { standalone: true }> & { inContextOf: Person; inContextOf: { Kind: Exclude<number, 0> }; } => { if (props.standalone) return true; // 排除standalone为true的情况后,TS已明确props属于另一分支类型 if (!props.inContextOf) return true; if (!IsEntityPerson(props.inContextOf)) return true; if (props.inContextOf.Kind === 0.0) return true; return false; };
这样修改后,当CheckAbortScenarios()返回false时,TypeScript就能准确推断出props满足:
standalone: falseinContextOf是存在的Person类型inContextOf.Kind不为0
此时Initialize函数中的代码就不会再报错,甚至不需要非空断言:
const Initialize = (): void => { if (CheckAbortScenarios()) return; // TS现在能正确推断inContextOf的类型 const kind = props.inContextOf.Kind; };
内容的提问来源于stack exchange,提问作者user17145524
相关产品推荐
相关产品推荐

