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

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;
      

3. TypeScript类型断言导致的误导

你可能用类型断言将普通对象强制转为Trade类型(比如const trade = apiData as Trade),TypeScript编译时不会报错,但运行时这个对象并非真正的Trade实例,自然没有getter属性。

  • 验证方式:在浏览器控制台打印Object.getOwnPropertyNames(trade),只会看到实例属性,看不到getter;而真正的Trade实例会在原型链上包含这些getter。
  • 修复方案:放弃类型断言,改用new Trade()创建实例,或者实现一个转换函数将普通对象转为Trade实例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 21:22:02