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

使用Decimal作为默认值时plainToInstance无法正常工作的问题排查

问题分析与解决方案

你的问题并非class-transformer的bug,而是由于对属性处理逻辑或Transform装饰器参数的理解偏差,或是使用了较旧版本的class-transformer导致的。

核心原因

在早期版本的class-transformer中,@Transform装饰器的obj参数指向的是正在创建的类实例,而非传入的普通对象。由于class-transformer默认不会调用类的构造函数,实例的totalDistance和attempts属性在Transform执行时还未被赋值(处于undefined状态),因此调用new Decimal(obj.totalDistance)会抛出参数无效的错误。

即使在新版本中,若属性处理顺序导致Transform先于其他属性赋值执行,也可能出现类似问题,但新版本已将obj参数改为指向传入的普通对象,因此可以直接获取到正确的totalDistance和attempts值。

解决方案

方案1:升级class-transformer到最新版本

升级到v0.5及以上版本后,原有代码即可正常工作,因为obj参数会指向传入的普通对象:

import { plainToInstance, Transform } from 'class-transformer';
import Decimal from 'decimal.js';

class MyClass {
  readonly attempts: number = 1;
  readonly totalDistance: number = 1;
  
  @Transform(({ obj }) => new Decimal(obj.totalDistance).div(obj.attempts))
  readonly distancePerAttempt: Decimal = new Decimal(0);
}

const instance = plainToInstance(MyClass, { attempts: 3, totalDistance: 30 });
console.log(instance.distancePerAttempt.toString()); // 输出 "10"

方案2:使用Getter属性替代Transform装饰器

如果无法升级版本,可将distancePerAttempt改为Getter属性,它会在访问时自动计算值,无需依赖Transform:

import { plainToInstance } from 'class-transformer';
import Decimal from 'decimal.js';

class MyClass {
  readonly attempts: number = 1;
  readonly totalDistance: number = 1;
  
  get distancePerAttempt(): Decimal {
    return new Decimal(this.totalDistance).div(this.attempts);
  }
}

const instance = plainToInstance(MyClass, { attempts: 3, totalDistance: 30 });
console.log(instance.distancePerAttempt.toString()); // 输出 "10"

方案3:通过构造函数计算属性值

使用useConstructor: true选项让class-transformer调用类的构造函数,在构造函数中直接计算distancePerAttempt:

import { plainToInstance } from 'class-transformer';
import Decimal from 'decimal.js';

class MyClass {
  readonly attempts: number;
  readonly totalDistance: number;
  readonly distancePerAttempt: Decimal;

  constructor({ attempts = 1, totalDistance = 1 }: Partial<MyClass> = {}) {
    this.attempts = attempts;
    this.totalDistance = totalDistance;
    this.distancePerAttempt = new Decimal(totalDistance).div(attempts);
  }
}

const instance = plainToInstance(MyClass, { attempts: 3, totalDistance: 30 }, { useConstructor: true });
console.log(instance.distancePerAttempt.toString()); // 输出 "10"

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 01:48:09