Typescript - 11. 装饰器(Decorators)

75 阅读2分钟

在 TypeScript 中,装饰器(Decorators)是一种特殊类型的声明,可以附加到类声明、方法、访问器、属性或参数上,以修改其行为或添加元数据。TypeScript 支持多种装饰器,包括类装饰器、方法装饰器、属性装饰器、访问器装饰器和参数装饰器。

类装饰器(Class Decorators)

类装饰器在类声明之前声明,并用 @ 符号应用于类声明之前。类装饰器可以用来:

  • 修改类的行为。
  • 修改类的构造函数。
  • 添加静态属性或方法。

例如,以下是一个简单的类装饰器示例:

function logged(constructorFn: Function) {
    console.log(constructorFn);
}

@logged
class Person {
    constructor() {
        console.log("Hi there!");
    }
}

在这个例子中,@logged 装饰器将 Person 类传递给 logged 函数,并输出构造函数 Person 的定义。

方法装饰器(Method Decorators)

方法装饰器应用于方法的声明之前,用来监视、修改或替换方法定义。它接收三个参数:目标对象、方法名和属性描述符。

function enumerable(value: boolean) {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        descriptor.enumerable = value;
    };
}

class Greeter {
    greeting: string;

    constructor(message: string) {
        this.greeting = message;
    }

    @enumerable(false)
    greet() {
        return "Hello, " + this.greeting;
    }
}

在这个例子中,@enumerable(false) 装饰器使 greet 方法变为不可枚举的,即不会出现在对象的属性列表中。

访问器装饰器(Accessor Decorators)

访问器装饰器应用于访问器的声明之前,用来监视、修改或替换访问器的定义。

function configurable(value: boolean) {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        descriptor.configurable = value;
    };
}

class Point {
    private _x: number = 0;
    private _y: number = 0;

    @configurable(false)
    get x() { return this._x; }

    @configurable(true)
    get y() { return this._y; }
}

在这个例子中,@configurable(false)@configurable(true) 装饰器分别用于 xy 访问器,设置它们的 configurable 属性。

属性装饰器(Property Decorators)

属性装饰器应用于属性的声明之前,用来监视、修改或替换属性的定义。

function format(target: any, propertyKey: string) {
    let value = target[propertyKey];

    const getter = function () {
        return value;
    };

    const setter = function (newVal: string) {
        value = `[ ${newVal} ]`;
    };

    Object.defineProperty(target, propertyKey, {
        get: getter,
        set: setter,
        enumerable: true,
        configurable: true
    });
}

class Greeter {
    @format
    message: string;

    constructor(message: string) {
        this.message = message;
    }
}

const greeter = new Greeter("world");
console.log(greeter.message); // Output: [ world ]

在这个例子中,@format 装饰器修改了 message 属性的 getter 和 setter 方法,使其在获取和设置时自动添加括号。

参数装饰器(Parameter Decorators)

参数装饰器应用于函数参数的声明之前,用来监视、修改或替换参数的定义。

function logParameter(target: any, propertyName: string, index: number) {
    const metadataKey = `log_${propertyName}_parameters`;
    if (Array.isArray(target[metadataKey])) {
        target[metadataKey].push(index);
    } else {
        target[metadataKey] = [index];
    }
}

class Calculator {
    add(@logParameter x: number, y: number): number {
        return x + y;
    }
}

const calc = new Calculator();
calc.add(1, 2); // Output: Logs [0] which indicates the index of the parameter decorated

在这个例子中,@logParameter 装饰器记录了 add 方法中第一个参数 x 的索引。

总结

TypeScript 的装饰器提供了一种强大的机制,可以以声明式的方式修改类和其成员的行为,或者添加额外的元数据。它们可以帮助开发者更加灵活和高效地组织和管理代码。然而,需要注意的是,装饰器目前仍处于实验性阶段,并可能在未来的 TypeScript 版本中发生变化。