javascript - 打字稿装饰器:将实例字段添加到类以在同一类中使用
问题描述
我目前正在学习 Typescript 装饰器。我的第一个目标是在一定程度上将 @Slf4J 从 Project Lombok 在 Java 中所做的复制到 Typescript。想法是用例如@logger 注释/装饰一个类,以在同一类中接收LogUtil 类型的字段日志,以便调用例如log.info()。
LogUtil 类:
export class LoggerUtil {
logLevel: LogLevel;
constructor(logLevel: LogLevel) {
this.logLevel = logLevel;
}
error(className: string, message: string) {
if (this.logLevel >= LogLevel.ERROR) {
console.error(`${new Date()} [ERROR] ${className}: ${message}`);
}
}
warn(className: string, message: string) {
if (this.logLevel >= LogLevel.WARN) {
console.log(`${new Date()} [WARN] ${className}: ${message}`);
}
}
log(className: string, message: string): void {
console.log(`${new Date()} [LOG] ${className} ${message}`)
}
info(className: string, message: string): void {
if (this.logLevel >= LogLevel.INFO) {
console.log(`${new Date()} [INFO] ${className}: ${message}`)
}
}
call(className: string, message: string) {
if (this.logLevel >= LogLevel.INFO) {
console.log(`${new Date()} [CALL] ${className}.${message}`)
}
}
debug(className: string, message: string) {
if (this.logLevel >= LogLevel.DEBUG) {
console.log(`${new Date()} [DEBUG] ${className}: ${message}`)
}
}
}
日志级别枚举:
export enum LogLevel {
ERROR = 0,
WARN = 1,
INFO = 2,
DEBUG = 3
}
使用 @logger 装饰器获取 LoggerUtil 实例作为日志的示例类
@logger
export class SomeService {
exampleFunction() {
log.info("exampleFunction called")
}
}
我目前正在尝试使用类级装饰器来做到这一点。在这里,我正在尝试做不同的事情:
使用 Reflect API 定义类的属性。在这里,我什至不确定这是否有效。
export function logger() {
return function(target: Function) {
Reflect.defineProperty(target, "log", { value: new LoggerUtil(LogLevel.DEBUG) } )
}
}
使用类原型定义属性:
export function logger() {
return function(target: Function) {
target.prototype.log = new LoggerUtil(LogLevel.DEBUG);
}
}
在引用服务中的日志实例时,使用每种方法我都会得到“找不到名称'log'”:
@logger
export class SomeService {
exampleFunction() {
log.info("exampleFunction called") // Cannot find name 'log'
}
}
我的想法可能吗?我缺少一些基本的东西吗?
非常感谢您提前提供任何反馈!
解决方案
我找到了一种至少可以满足我需求的方法:
我选择了继承(我想避免)。请参见下面的示例:
@logger
export class SomeService extends Logger {
constructor() {
super()
}
exampleFunction() {
log.info("exampleFunction called")
}
}
然后我扩展的超类看起来像这样:
@logger
export class Logger {
log: LoggerUtil;
}
最后,装饰器看起来像这样:
export function logger<T extends {new(...args:any[]):{}}>(constructor:T) {
return class extends constructor {
log = new LoggerUtil(LogLevel.DEBUG);
}
}
我的想法是通过继承将字段日志添加到SomeService 。现在要初始化这个字段,我在超类上使用了装饰器。装饰器本身返回一个类,该类使用初始化字段扩展装饰器类。这样就创建了以下继承图:
@logger(装饰器)-> Logger(超类)-> SomeService。
我本可以在超类Logger本身中初始化日志字段。然而,这是为了研究装饰器并希望从长远来看消除超类。
作为参考,我想指出有关如何覆盖构造函数的Typescript 文档。
推荐阅读
- c# - 如何从树资源中隐藏日试点计划程序的白框图标?
- java - 如果在 Thymeleaf 中使用 AND/OR
- flutter - 等待小部件加载其组件
- javascript - 无法在 React 中导入类
- java - 如何从java中的字符串中删除\"?
- sonarqube - 使用 SonarQube Web API 检索条件覆盖信息
- mysql - SQL 为每个 userID 记录计数一个值,除非 userId 的一个记录值为 x
- python - 从具有精确单词匹配的句子列表中获取句子:Python
- javascript - 选择加选项下拉列表播放音频文件
- facebook - Facebook 返回“此网页包含被阻止的 URL”