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

使用Class Transformer处理嵌套数组对象的多Expose问题

Class Transformer嵌套数组转换问题的解决方案

问题分析

你遇到的核心问题是:在Product类中,两个字段book1和book2都通过@Expose({ name: 'data' })映射到源对象的同一个data字段,Class Transformer处理时会出现字段覆盖,最终只有最后一个字段的转换生效。

正确实现方式

方式一:顶层类直接转换生成目标结构

这种方式无需拆分嵌套类,直接在顶层类中对整个输入结构做转换,更贴合你的期望输出:

import { Expose, Transform, plainToClassFromExist } from 'class-transformer';

export class TargetData {
  @Expose({ name: 'data' })
  @Transform(({ obj }) => {
    // 遍历products数组,逐个处理每个product的books
    return obj.products.map(product => {
      const bookExistMap: Record<string, boolean> = {};
      // 若仅需检测指定书籍(如book1、book2),可替换为逐个判断
      // bookExistMap.book1 = product.data.books.some(book => book.name === 'book1');
      // bookExistMap.book2 = product.data.books.some(book => book.name === 'book2');
      
      // 若要自动识别所有书籍名称,用以下逻辑
      product.data.books.forEach(book => {
        bookExistMap[book.name] = true;
      });
      return bookExistMap;
    });
  })
  data: Array<Record<string, boolean>>;

  constructor(partial: Partial<TargetData>) {
    plainToClassFromExist(this, partial);
  }
}

// 使用示例
const input = {
  "products": [
    {
      "data": {
        "books": [
          { "name": "book1", "type": "hardcover" },
          { "name": "book2", "type": "hardcover" }
        ]
      }
    }  
  ]
};

const result = new TargetData(input);
console.log(result);
// 输出:{ data: [ { book1: true, book2: true } ] }

方式二:优化嵌套类结构

如果需要保留类的分层结构,可调整Product类的逻辑,用单个字段接收data并转换为目标对象,再在顶层类中整理成数组:

import { Expose, Transform, Type, plainToClassFromExist } from 'class-transformer';

export class Product {
  @Expose()
  @Transform(({ value }) => {
    const bookExistMap: Record<string, boolean> = {};
    value.books.forEach(book => {
      bookExistMap[book.name] = true;
    });
    // 或指定仅检测book1、book2
    // bookExistMap.book1 = value.books.some(b => b.name === 'book1');
    // bookExistMap.book2 = value.books.some(b => b.name === 'book2');
    return bookExistMap;
  })
  @Expose({ name: 'data' })
  transformedData: Record<string, boolean>;
}

export class Products {
  @Expose({ name: 'data' })
  @Transform(({ value }) => value.map(p => p.transformedData))
  @Type(() => Product)
  @Expose({ name: 'products' })
  products: Product[];

  constructor(partial: Partial<Products>) {
    plainToClassFromExist(this, partial);
  }
}

// 使用示例
const input = { /* 同之前的输入 */ };
const result = new Products(input);
console.log(result);
// 输出:{ data: [ { book1: true, book2: true } ] }

关键说明

  • 避免多个字段通过@Expose映射到同一个源字段,这会导致字段覆盖问题。
  • 使用Transform时,可通过obj参数获取整个源对象(方式一),或通过value获取当前字段的值(方式二),灵活处理嵌套结构。
  • 若只需要检测固定的书籍名称(如book1、book2),推荐用Array.some()替代filter().length > 0,逻辑更简洁高效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 11:47:35