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

TypeScript/React中Props联合类型访问子属性失效求助

问题描述

我定义了以下类型,其中CurrencyStat和ScoreStat继承自Stat:

export interface Stat {
  value: number;
  change?: number;
}

type Currency = "USD" | "RMB";

export interface CurrencyStat extends Stat {
  currency: Currency;
}

export interface ScoreStat extends Stat {
 outof: number;
}

我尝试编写StatDisplay组件兼容所有Stat类型,当把stat Prop设为Stat | CurrencyStat联合类型时,出现错误:

Property 'currency' does not exist on type 'Stat | CurrencyStat'. Property 'currency' does not exist on type 'Stat'.ts(2339)

我知道联合类型只能访问所有类型共有的成员,但不想把currency设为Stat的可选属性并删除CurrencyStat——后续会新增更多Stat类型,希望保持类型独立,求可行解决方案。

组件代码如下:

import { CurrencyStat, ScoreStat, Stat } from "../../../../types/types";
export const StatDisplay = ({
  label,
  stat,
}: {
  label: string;
  stat: Stat | CurrencyStat;
}) => {
  return (
    <div className="flex flex-col items-center">
      <div className="flex items-center">
        <div className="">{stat?.currency}</div>
        <div className="text-2xl font-semibold">{stat.value}</div>
      </div>
      <div className="">{label}</div>
    </div>
  );
};
解决方案

方法1:自定义类型守卫

编写类型守卫函数,显式判断stat是否为CurrencyStat,让TypeScript在条件分支中自动缩小类型范围:

// 自定义类型守卫函数
function isCurrencyStat(stat: Stat | CurrencyStat): stat is CurrencyStat {
  return (stat as CurrencyStat).currency !== undefined;
}

export const StatDisplay = ({
  label,
  stat,
}: {
  label: string;
  stat: Stat | CurrencyStat;
}) => {
  return (
    <div className="flex flex-col items-center">
      <div className="flex items-center">
        {/* 通过类型守卫确认类型后再访问currency */}
        {isCurrencyStat(stat) && <div className="">{stat.currency}</div>}
        <div className="text-2xl font-semibold">{stat.value}</div>
      </div>
      <div className="">{label}</div>
    </div>
  );
};

方法2:添加判别式的联合类型(推荐,适配后续扩展)

给每个Stat子类型添加唯一的type字段作为判别标识,让TypeScript自动识别不同类型,后续新增类型只需补充对应判别式即可:

首先修改类型定义:

export interface Stat {
  value: number;
  change?: number;
}

type Currency = "USD" | "RMB";

export interface CurrencyStat extends Stat {
  type: "currency"; // 新增判别式
  currency: Currency;
}

export interface ScoreStat extends Stat {
  type: "score"; // 新增判别式
  outof: number;
}

// 统一导出包含所有Stat类型的联合类型
export type AnyStat = Stat | CurrencyStat | ScoreStat;

然后修改组件:

import { AnyStat } from "../../../../types/types";
export const StatDisplay = ({
  label,
  stat,
}: {
  label: string;
  stat: AnyStat;
}) => {
  return (
    <div className="flex flex-col items-center">
      <div className="flex items-center">
        {/* 通过判别式自动识别类型 */}
        {stat.type === "currency" && <div className="">{stat.currency}</div>}
        {/* 后续新增类型直接添加对应分支即可 */}
        {stat.type === "score" && <div className="">/{stat.outof}</div>}
        <div className="text-2xl font-semibold">{stat.value}</div>
      </div>
      <div className="">{label}</div>
    </div>
  );
};

方法3:类型断言(不推荐,不安全)

可以用类型断言强制告诉TypeScript当前stat是CurrencyStat,但这种方式会跳过类型检查,若传入普通Stat会引发运行时错误,仅适合临时应急:

<div className="">{(stat as CurrencyStat)?.currency}</div>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 12:39:23