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

React组件中API响应类型化与条件渲染的TypeScript报错问题

TypeScript联合类型条件渲染报错的原因与解决办法

你遇到的这个报错其实是TypeScript类型窄化的一个常见坑——当你把类型判断的结果存在单独的布尔变量里时,TypeScript没办法把这个变量和原对象的类型关联起来。

具体来说,你预先定义的isPostalAddress和isPackstationAddress只是普通的布尔值,TypeScript不会记住它们是通过检查deliveryAddress.type得到的。所以当你在JSX里用这些变量做条件判断时,TypeScript无法确定此时deliveryAddress的具体类型,它仍然会把deliveryAddress当成PostalAddress | PackstationAddress的联合类型,自然会报错说street/packstation这些属性可能在另一种类型中不存在。

下面给你几种实用的解决办法:


1. 直接在JSX条件中做类型判断(最简单直接)

把类型检查逻辑直接写在JSX的条件表达式里,这样TypeScript能实时对deliveryAddress进行类型窄化:

return (
  <div className="App">
    {props.deliveryAddress.type === AddressType.postal && (
      <>
        <h2>Street: {props.deliveryAddress.street}</h2>
        <h2>Street Number: {props.deliveryAddress.streetNumber}</h2>
      </>
    )}
    {props.deliveryAddress.type === AddressType.packstation && (
      <>
        <h2>Packstation: {props.deliveryAddress.packstation}</h2>
        <h2>Post Number: {props.deliveryAddress.postNumber}</h2>
      </>
    )}
  </div>
);

2. 自定义类型守卫函数(适合需要复用判断逻辑的场景)

如果希望保留预先判断的逻辑,可以写一个类型守卫函数,明确告诉TypeScript判断结果对应的类型:
首先在types.ts中添加守卫函数:

export function isPostalAddress(address: DeliveryAddress): address is PostalAddress {
  return address.type === AddressType.postal;
}

export function isPackstationAddress(address: DeliveryAddress): address is PackstationAddress {
  return address.type === AddressType.packstation;
}

然后在组件中使用:

const DeliveryAddressDisplay = (props: Props) => {
  const address = props.deliveryAddress;
  const isPostal = isPostalAddress(address);
  const isPackstation = isPackstationAddress(address);

  return (
    <div className="App">
      {isPostal && <h2>Street: {address.street}</h2>}
      {isPackstation && <h2>Packstation: {address.packstation}</h2>}
      {isPostal && <h2>Street Number: {address.streetNumber}</h2>}
      {isPackstation && <h2>Post Number: {address.postNumber}</h2>}
    </div>
  );
};

类型守卫函数的关键在于返回值类型address is PostalAddress,它会告诉TypeScript:如果这个函数返回true,那么传入的address一定是PostalAddress类型。


3. 使用switch语句做分支覆盖(最严谨)

switch语句是TypeScript处理联合类型的绝佳场景,它能自动完成类型窄化,还能确保所有分支都被覆盖:

const DeliveryAddressDisplay = (props: Props) => {
  const address = props.deliveryAddress;

  return (
    <div className="App">
      {(() => {
        switch(address.type) {
          case AddressType.postal:
            return (
              <>
                <h2>Street: {address.street}</h2>
                <h2>Street Number: {address.streetNumber}</h2>
              </>
            );
          case AddressType.packstation:
            return (
              <>
                <h2>Packstation: {address.packstation}</h2>
                <h2>Post Number: {address.postNumber}</h2>
              </>
            );
          default:
            // 这里可以抛出错误或者渲染默认内容,确保没有遗漏的类型分支
            throw new Error(`Unsupported address type: ${address.type}`);
        }
      })()}
    </div>
  );
};

这种方式的好处是,如果后续你扩展了AddressType,TypeScript会立刻提示你在switch中添加对应的处理分支,避免遗漏。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:04:28