TypeScript类内this访问属性与外部实例属性值不一致问题
问题根因
这个问题和decimal.js类型无关,核心原因是你将toDto写成了类实例字段形式的箭头函数,结合项目中常见的对象代理/包装逻辑(Vue3/MobX响应式、ORM实体包装、immer不可变更新、class-transformer等序列化工具都有这类逻辑),导致this指向和你外部观测的实例不一致:
- 类字段箭头函数会在构造函数执行阶段,为每个实例单独创建一个函数,这个函数的
this会被永久绑定到刚创建的原始未包装实例上,无法被后续的代理、bind、call修改。 - 当实例被上述工具处理后,你在外部断点观测到的实际是原始实例的代理/包装对象,看到的
currentBalance=2957.86是代理对象上的属性值,原始实例上的该属性还停留在初始化时的0。 - 调用代理对象的
toDto方法时,由于代理本身没有重写该方法,会找到原始实例上绑定的箭头函数执行,此时this指向原始实例,自然读到的是0值。 - 你将实例作为
source参数传入时,访问的是传入的代理对象本身的属性,因此能拿到正确值。
另外你当前构造函数的判断逻辑存在隐性bug:用if (xxx.currentBalance)做判断时,合法的0值会被判定为false,错误走默认赋值逻辑。
标准修复方案
将箭头函数形式的类字段方法改为定义在原型上的普通类方法即可。普通类方法的this是调用时动态绑定的,谁调用方法this就指向谁,在代理对象上调用时会正确指向代理对象,读到最新的属性值:
export class LedgerAccount { currentBalance: Decimal; constructor(request: CreateLedgerAccountRequest | LedgerAccountDto) { // 修复原判断的0值误判问题 if ((request as LedgerAccountDto).currentBalance !== undefined) { this.currentBalance = new Decimal((request as LedgerAccountDto).currentBalance); } else { this.currentBalance = new Decimal(0); } } // 改为普通原型方法,不要用箭头函数赋值 toDto(): LedgerAccountDto { const result: LedgerAccountDto = { currentBalance: this.currentBalance.toNumber(), }; return result; } }
如果确实有固定this的需求(比如需要把方法直接作为回调传递,避免丢失this),可以在构造函数中显式绑定,而不是用类字段箭头函数:
constructor(request: CreateLedgerAccountRequest | LedgerAccountDto) { // ...原有初始化逻辑 this.toDto = this.toDto.bind(this); }
注意这种绑定方式如果遇到代理场景依然会有this指向原始对象的问题,非必要不使用。
内容的提问来源于stack exchange,提问作者Misanthropist
相关产品推荐
相关产品推荐

