NestJS CQRS:如何简洁地将DTO对象作为命令构造参数传递
解决方案
问题出在两个核心点:一是之前泛型参数错误地使用了子类自身,导致类型不匹配且会复制payload的所有属性;二是直接用Object.assign会把payload里的冗余字段(比如type)也赋值给命令实例,同时子类声明的未初始化属性会错误覆盖传入的有效值。
可以通过修改抽象命令类的构造函数,仅复制子类实例的自有属性来解决,既过滤多余字段,又确保属性正确赋值:
export class AbstractCommand<T> implements ICommand { constructor(args: T) { // 获取当前子类实例的自有属性(即子类中声明的属性) const ownPropertyNames = Object.getOwnPropertyNames(this); // 仅复制args中与子类自有属性匹配的键值对 ownPropertyNames.forEach(prop => { if (Object.prototype.hasOwnProperty.call(args, prop)) { // 类型断言绕过readonly编译检查,构造函数内允许赋值 (this as Record<string, unknown>)[prop] = (args as Record<string, unknown>)[prop]; } }); } } // 子类保持原有定义,泛型参数改为传入的Payload类型 export class CreateProductTypeACommand extends AbstractCommand<Payload> { public readonly name?: string; }
使用示例:
const payload: Payload = { type: 'typeA', name: 'Product A' }; const command = new CreateProductTypeACommand(payload); // command 仅包含name属性,值为'Product A',无type字段
原理说明
- 泛型修正:将抽象类的泛型参数改为实际传入的
Payload类型,确保类型匹配且符合初始化逻辑。 - 属性过滤:通过
Object.getOwnPropertyNames(this)获取子类声明的所有自有属性,只复制payload中对应的属性,自动过滤type这类冗余字段。 - 避免覆盖:主动赋值匹配的属性,不会被子类未初始化的
undefined覆盖,同时保留readonly的编译时约束。
内容的提问来源于stack exchange,提问作者PlantBasedDeveloper
相关产品推荐
相关产品推荐

