javascript - typescript 装饰器 : Add instance field t

我目前正在学习 Typescript 装饰器。我的第一个目标是将 Lombok 项目中的 @Slf4J 在 Java 中对 Typescript 所做的工作进行某种程度的重现。想法是用例如注释/装饰一个类@logger 在同一类中接收类型为 LogUtil 的字段log,以便调用例如日志信息()。

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}`)
        }
    }
}

LogLevel 枚举:

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) } )
    }
}

使用类原型(prototype)定义属性:

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")
    }
}

然后我扩展的父类(super class)看起来像这样:

@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);
    }
}

我的想法是通过继承将字段log 添加到SomeService。现在为了初始化这个字段,我在父类(super class)上使用了装饰器。装饰器本身返回一个类,该类使用初始化字段扩展装饰器类。这样就创建了以下继承图:

@logger(装饰器)-> Logger(父类(super class))-> SomeService。

我可以在父类(super class) Logger 本身中初始化 log 字段。然而,这是为了研究装饰器,并希望从长远来看消除父类(super class)。

作为引用,我想指出 Typescript documentation关于如何覆盖构造函数。

关于javascript - typescript 装饰器 : Add instance field to class to use within the same class,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60913189/

相关文章:

tensorflow - Tensorflow text_generation 教程中有状态 GRU

scala - 在 Akka Streams 中模拟源

python - np.array 到 PIL 图像 --> Typerror : Cannot h

ag-grid - 如何在 Ag-Grid 中将相同的相邻行与动态行跨度合并?

react-native - 我可以通过 expo 获得在 android 上工作的 webpack

python - 在 OR 工具中使用 IntVar

reactjs - 尝试使用 React-Spring 制作动画时出现错误 "TypeError:

c# - 如何从工作流对话框中删除标题中的问号?

qt - 如何在使用 AUTORCC 的 CMake 项目中使用 qtquick_compiler_

javascript - 为什么ioredis客户端开启keep-alive会超时?