TypeScript类getter属性在浏览器中始终返回undefined问题排查
问题:TypeScript类的Getter属性在浏览器中返回undefined,Jest测试却正常
我定义了如下TypeScript类Trade:
import { Security } from 'models/Security' export type TradeType = | 'Buy' | 'Reinvest' | 'Sell' | 'Dividend' | 'Stock Split' | 'Starting Value' | null type PositiveTradeType = | 'Buy' | 'Reinvest' | 'Dividend' | 'Stock Split' | 'Starting Value' export interface ITrade { id?: number accountId: number settledOn: string tradeType: TradeType shares: number security?: Security priceCents: number basis?: number gain?: number securityId: number } export class Trade implements ITrade { id?: number accountId: number settledOn: string tradeType: TradeType shares: number security?: Security priceCents: number basis?: number gain?: number securityId: number constructor( accountId: number, settledOn: string, tradeType: TradeType, shares: number, priceCents: number, securityId: number, id?: number, security?: Security, basis?: number, gain?: number ) { this.id = id this.accountId = accountId this.settledOn = settledOn this.tradeType = tradeType this.shares = shares this.security = security this.priceCents = priceCents this.basis = basis this.gain = gain this.securityId = securityId } get holdingImpact(): number { if (!this.tradeType) { return 0 } return this.isOfPositiveType(this.tradeType) ? this.shares : -this.shares } get settledOnDate(): Date { return new Date(this.settledOn) } isOfPositiveType(tradeType: string): tradeType is PositiveTradeType { return [ 'Buy', 'Reinvest', 'Dividend', 'Stock Split', 'Starting Value', ].includes(tradeType) } }
在Chrome和Firefox浏览器中,访问该类实例的holdingImpact或settledOnDate等getter属性时,始终返回undefined(通过console.log或调试器均如此)。但在Jest测试中,这些属性工作正常。项目由create-react-app创建,tsconfig配置如下:
{ "compilerOptions": { "target": "es6", "incremental": true, "baseUrl": "./src", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "strict": true, "forceConsistentCasingInFileNames": true, "noFallthroughCasesInSwitch": true, "module": "esnext", "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "react-jsx", "downlevelIteration": true }, "include": ["src/**/*"] }
请问可能是什么原因导致该问题?
可能的原因及解决方案
1. 实例并非Trade类的真正实例,而是普通JavaScript对象
这是最常见的原因:你在浏览器中使用的"Trade实例",实际是从API响应、Redux状态、JSON.parse或其他序列化流程得到的普通对象,而非通过new Trade(...)创建的类实例。这类对象仅包含Trade类的属性字段,但不会继承Trade原型链上的方法和getter。
- Jest测试中你直接用
new Trade()创建实例,自然能正常访问getter;但浏览器中如果是普通对象,调用trade instanceof Trade会返回false。 - 修复方案:将普通对象转换为Trade实例,比如:
// 假设tradeData是从API获取的普通对象 const validTradeInstance = new Trade( tradeData.accountId, tradeData.settledOn, tradeData.tradeType, tradeData.shares, tradeData.priceCents, tradeData.securityId, tradeData.id, tradeData.security, tradeData.basis, tradeData.gain );
2. 生产环境代码压缩/Tree Shaking误删了getter
create-react-app生产环境打包时,webpack配合Terser会做代码优化,如果静态分析认为getter未被使用,可能会将其移除。
- 验证方式:切换到开发模式(
npm start)测试,如果开发模式正常,生产模式出问题,基本可以确定是压缩优化导致。 - 修复方案:
- 在getter上添加
/*#__PURE__*/注释,告诉打包工具该getter是纯函数,不应被移除:get /*#__PURE__*/ holdingImpact(): number { // 原代码逻辑 } - 或者在代码的某个位置显式引用该getter(哪怕是空操作),让打包工具识别到它被使用:
// 随便找个地方添加,比如组件初始化时 const _ = trade.holdingImpact;
- 在getter上添加
3. TypeScript类型断言导致的误导
你可能用类型断言将普通对象强制转为Trade类型(比如const trade = apiData as Trade),TypeScript编译时不会报错,但运行时这个对象并非真正的Trade实例,自然没有getter属性。
- 验证方式:在浏览器控制台打印
Object.getOwnPropertyNames(trade),只会看到实例属性,看不到getter;而真正的Trade实例会在原型链上包含这些getter。 - 修复方案:放弃类型断言,改用
new Trade()创建实例,或者实现一个转换函数将普通对象转为Trade实例。
内容的提问来源于stack exchange,提问作者Mark Fraser
相关产品推荐
相关产品推荐

