You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

抽离属性检查至函数后,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: false
  • inContextOf是存在的Person类型
  • inContextOf.Kind不为0

此时Initialize函数中的代码就不会再报错,甚至不需要非空断言:

const Initialize = (): void => {
  if (CheckAbortScenarios()) return;

  // TS现在能正确推断inContextOf的类型
  const kind = props.inContextOf.Kind;
};

内容的提问来源于stack exchange,提问作者user17145524

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 05:27:35