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
相关产品推荐
相关产品推荐

