class-transformer装饰器详解:@Expose与@Exclude的高级应用
【免费下载链接】class-transformer 项目地址: https://gitcode.com/gh_mirrors/cla/class-transformer
在TypeScript开发中,处理对象序列化(Serialization)和反序列化(Deserialization)时,我们经常需要控制哪些属性应该被包含或排除。class-transformer库提供了强大的装饰器(Decorator)机制来实现这一需求,其中最基础也最常用的就是@Expose和@Exclude。本文将深入解析这两个装饰器的工作原理、高级用法及实际应用场景,帮助开发者在项目中灵活控制对象的属性可见性。
核心装饰器基础:@Expose与@Exclude的定义
@Expose和@Exclude是class-transformer中用于控制属性暴露与排除的核心装饰器,定义于src/decorators/expose.decorator.ts和src/decorators/exclude.decorator.ts文件中。
@Expose装饰器
@Expose用于标记类或属性为“包含”状态,默认情况下会在序列化(classToPlain) 和反序列化(plainToClass) 两个方向生效。其核心实现逻辑如下:
export function Expose(options: ExposeOptions = {}): PropertyDecorator & ClassDecorator {
return function (object: any, propertyName?: string | Symbol): void {
defaultMetadataStorage.addExposeMetadata({
target: object instanceof Function ? object : object.constructor,
propertyName: propertyName as string,
options,
});
};
}
通过options参数可限制其作用方向,例如:
toPlainOnly: true:仅在序列化(类实例→普通对象)时暴露toClassOnly: true:仅在反序列化(普通对象→类实例)时暴露
@Exclude装饰器
@Exclude与@Expose相反,用于标记类或属性为“排除”状态,默认同样作用于两个方向。其实现与@Expose类似:
export function Exclude(options: ExcludeOptions = {}): PropertyDecorator & ClassDecorator {
return function (object: any, propertyName?: string | Symbol): void {
defaultMetadataStorage.addExcludeMetadata({
target: object instanceof Function ? object : object.constructor,
propertyName: propertyName as string,
options,
});
};
}
同样支持toPlainOnly和toClassOnly选项控制作用方向。
基础用法:属性级别的包含与排除
场景1:排除敏感属性
在用户信息类中,密码等敏感字段需要在序列化时排除。例如sample/sample2-iheritance/Album.ts中的实现:
export class Album {
id: number;
name: string;
@Exclude() // 默认在序列化和反序列化时均排除
private secretKey: string; // 敏感字段不参与转换
}
场景2:暴露只读计算属性
对于需要在序列化时暴露但无需反序列化的计算属性,可使用@Expose({ toPlainOnly: true }):
export class User {
firstName: string;
lastName: string;
@Expose({ toPlainOnly: true })
get fullName(): string {
return `${this.firstName} ${this.lastName}`;
}
}
高级应用:类级装饰与方向控制
类级@Exclude与属性级@Expose的组合
当整个类被标记为@Exclude时,默认会排除所有属性,此时可通过@Expose手动指定需要包含的属性:
@Exclude() // 类级排除:默认所有属性不参与转换
export class User {
@Expose() // 显式暴露id
id: number;
@Expose({ toClassOnly: true }) // 仅反序列化时暴露
password: string;
// 未标记@Expose,默认被排除
private internalCode: string;
}
方向控制示例
通过toPlainOnly和toClassOnly实现精细化控制:
export class User {
@Expose({ toPlainOnly: true }) // 仅序列化暴露(对外展示)
createdAt: Date;
@Expose({ toClassOnly: true }) // 仅反序列化暴露(接收输入)
password: string;
@Exclude({ toPlainOnly: true }) // 序列化时排除(内部使用)
lastLoginIp: string;
}
实战案例:继承场景下的装饰器应用
在sample/sample2-iheritance/目录中,展示了继承场景下装饰器的使用。例如Album类继承自Authorable接口,并排除了特定属性:
import { Exclude } from '../../src/decorators';
import { Authorable } from './Authorable';
export class Album implements Authorable {
id: number;
name: string;
authorId: number;
@Exclude() // 排除内部管理字段
_metadata: Record<string, any>;
}
转换效果验证
使用sample/sample1-simple-usage/app.ts中的转换逻辑验证效果:
// 序列化:类实例→普通对象
const userInstance = new User();
const plainObject = classToPlain(userInstance);
// plainObject中将不包含被@Exclude标记的属性
// 反序列化:普通对象→类实例
const jsonData = { id: '1', password: 'secret' };
const user = plainToClass(User, jsonData);
// user实例中仅包含@Expose或未被排除的属性
常见问题与解决方案
问题1:装饰器不生效
可能原因:
- 未启用TypeScript装饰器支持(需在
tsconfig.json中配置experimentalDecorators: true) - 转换时未使用class-transformer提供的
plainToClass或classToPlain方法
解决方案:
// 确保正确导入转换方法
import { plainToClass, classToPlain } from '../../src/index';
问题2:继承属性的排除规则
当父类和子类同时使用装饰器时,子类装饰器会覆盖父类规则。例如:
class Parent {
@Exclude()
id: number;
}
class Child extends Parent {
@Expose() // 覆盖父类的@Exclude,使id属性暴露
id: number;
}
总结与最佳实践
- 敏感字段必排除:用户密码、令牌等敏感信息必须用
@Exclude排除 - 方向控制优先:优先使用
toPlainOnly/toClassOnly明确作用方向 - 类级排除慎用:类级
@Exclude会增加维护成本,建议优先使用属性级装饰器 - 继承场景注意覆盖规则:子类装饰器会覆盖父类同名属性的规则
通过合理组合@Expose与@Exclude,可在前后端数据交互、日志输出、缓存存储等场景中灵活控制对象的属性可见性,提升代码安全性和数据处理效率。完整装饰器实现可参考src/decorators/目录源码,更多使用示例见test/functional/目录下的测试用例。
【免费下载链接】class-transformer 项目地址: https://gitcode.com/gh_mirrors/cla/class-transformer
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



