使用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
相关产品推荐
相关产品推荐

