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

如何通过纯装饰器方式实现扁平对象转嵌套class-transformer实例?

问题描述

我定义了如下3个类:

class Server {
    @Expose({ name: 'APP_PORT' })
    @Type(() => Number)
    port: number

    @Expose({ name: 'APP_TAG' })
    @Type(() => String)
    tag: string
}

class Database {
    @Expose({ name: 'DATABASE_PORT' })
    @Type(() => Number)
    port: number

    @Expose({ name: 'DATABASE_NAME' })
    @Type(() => String)
    name: string
}

class Global {
    @Type(() => Server)
    server: Server

    @Type(() => Database)
    database: Database
}

使用以下代码将扁平结构的plainObject转换为类实例:

import { plainToInstance } from 'class-transformer'

const plainObject = {
    APP_PORT: 5000,
    APP_TAG: '1.0.1',
    DATABASE_PORT: 8000,
    DATABASE_NAME: 'test',
}

const instance = plainToInstance(Global, plainObject)
console.log(instance)

返回结果不符合预期:

Global {
  server: undefined,   
  database: undefined, 
  APP_PORT: 5000,      
  APP_TAG: '1.0.1',    
  DATABASE_PORT: 8000, 
  DATABASE_NAME: 'test',
}

期望得到的结果:

Global {
  server: {
    APP_PORT: 5000,
    APP_TAG: '1.0.1',
  },
  database: {
    DATABASE_PORT: 8000,
    DATABASE_NAME: 'test',
  },
}

补充说明:曾通过修改plainObject结构临时解决,但希望仅通过调整类的装饰器实现需求。

解决方案

要实现从扁平对象到嵌套类实例的转换,需要给Global类的server和database属性添加@Transform装饰器,手动从扁平对象中提取对应字段并转换为子类实例,同时配合@Expose确保属性被正确处理。

修改后的完整类代码如下:

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

class Server {
    @Expose({ name: 'APP_PORT' })
    @Type(() => Number)
    port: number

    @Expose({ name: 'APP_TAG' })
    @Type(() => String)
    tag: string
}

class Database {
    @Expose({ name: 'DATABASE_PORT' })
    @Type(() => Number)
    port: number

    @Expose({ name: 'DATABASE_NAME' })
    @Type(() => String)
    name: string
}

class Global {
    @Expose()
    @Type(() => Server)
    @Transform(({ obj }) => plainToInstance(Server, obj))
    server: Server

    @Expose()
    @Type(() => Database)
    @Transform(({ obj }) => plainToInstance(Database, obj))
    database: Database
}

关键调整说明

  1. @Expose():显式标记server和database属性为转换过程中需要处理的字段,避免被默认规则忽略。
  2. @Transform():利用转换上下文获取原始扁平对象,调用plainToInstance将整个扁平对象转换为对应子类的实例——因为子类的@Expose已经映射了对应的扁平字段名,会自动匹配提取所需字段。
  3. @Type():辅助工具识别子类的类型,保证类型转换的准确性。

验证与预期输出

运行原转换代码后,会得到嵌套的类实例:

Global {
  server: Server { port: 5000, tag: '1.0.1' },
  database: Database { port: 8000, name: 'test' }
}

如果需要输出时保留原始的APP_PORT等字段名而非类属性名,可以使用instanceToPlain处理转换后的实例:

import { instanceToPlain } from 'class-transformer'

const instance = plainToInstance(Global, plainObject)
console.log(instanceToPlain(instance))

输出结果将完全符合预期:

{
  server: {
    APP_PORT: 5000,
    APP_TAG: '1.0.1',
  },
  database: {
    DATABASE_PORT: 8000,
    DATABASE_NAME: 'test',
  },
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 19:43:17