今天看啥  ›  专栏  ›  2o壹9

TypeScript——装饰器(三)

2o壹9  · 简书  ·  · 2019-12-23 09:24

访问器装饰器

访问器装饰器声明在一个访问器的声明之前(紧靠着访问器声明)。 访问器装饰器应用于访问器的 属性描述符并且可以用来监视,修改或替换一个访问器的定义。 访问器装饰器不能用在声明文件中(.d.ts),或者任何外部上下文(比如 declare的类)里。

注意  TypeScript不允许同时装饰一个成员的get和set访问器。取而代之的是,一个成员的所有装饰的必须应用在文档顺序的第一个访问器上。这是因为,在装饰器应用于一个属性描述符时,它联合了get和set访问器,而不是分开声明的。

访问器装饰器表达式会在运行时当作函数被调用,传入下列3个参数:

对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。

成员的名字。

成员的属性描述符。

注意  如果代码输出目标版本小于ES5,Property Descriptor将会是undefined。

如果访问器装饰器返回一个值,它会被用作方法的属性描述符。

注意  如果代码输出目标版本小于ES5返回值会被忽略。

下面是使用了访问器装饰器(@configurable)的例子,应用于Point类的成员上:

class Point {

private _x: number;

private _y: number;

constructor(x: number, y: number) {

this._x = x;

this._y = y;

}

@configurable(false)

get x() { return this._x; }

@configurable(false)

get y() { return this._y; }

}

我们可以通过如下函数声明来定义@configurable装饰器:

function configurable(value: boolean) {

return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {

descriptor.configurable = value;

};

}

属性装饰器

属性装饰器声明在一个属性声明之前(紧靠着属性声明)。 属性装饰器不能用在声明文件中(.d.ts),或者任何外部上下文(比如 declare的类)里。

属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数:

对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。

成员的名字。

注意  属性描述符不会做为参数传入属性装饰器,这与TypeScript是如何初始化属性装饰器的有关。 因为目前没有办法在定义一个原型对象的成员时描述一个实例属性,并且没办法监视或修改一个属性的初始化方法。返回值也会被忽略。因此,属性描述符只能用来监视类中是否声明了某个名字的属性。

我们可以用它来记录这个属性的元数据,如下例所示:

class Greeter {

@format("Hello, %s")

greeting: string;

constructor(message: string) {

this.greeting = message;

}

greet() {

let formatString = getFormat(this, "greeting");

return formatString.replace("%s", this.greeting);

}

}

然后定义@format装饰器和getFormat函数:

import "reflect-metadata";

const formatMetadataKey = Symbol("format");

function format(formatString: string) {

return Reflect.metadata(formatMetadataKey, formatString);

}

function getFormat(target: any, propertyKey: string) {

return Reflect.getMetadata(formatMetadataKey, target, propertyKey);

}

这个@format("Hello, %s")装饰器是个 装饰器工厂。 当 @format("Hello, %s")被调用时,它添加一条这个属性的元数据,通过reflect-metadata库里的Reflect.metadata函数。 当 getFormat被调用时,它读取格式的元数据。

注意  这个例子需要使用reflect-metadata库。 查看 元数据了解reflect-metadata库更详细的信息。




原文地址:访问原文地址
快照地址: 访问文章快照