美文网首页让前端飞
TypeScript——装饰器(四)

TypeScript——装饰器(四)

作者: 2o壹9 | 来源:发表于2019-12-24 08:57 被阅读0次

参数装饰器

参数装饰器声明在一个参数声明之前(紧靠着参数声明)。 参数装饰器应用于类构造函数或方法声明。 参数装饰器不能用在声明文件(.d.ts),重载或其它外部上下文(比如 declare的类)里。

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

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

成员的名字。

参数在函数参数列表中的索引。

注意  参数装饰器只能用来监视一个方法的参数是否被传入。

参数装饰器的返回值会被忽略。

下例定义了参数装饰器(@required)并应用于Greeter类方法的一个参数:

class Greeter {

    greeting: string;

    constructor(message: string) {

        this.greeting = message;

    }

    @validate

    greet(@required name: string) {

        return "Hello " + name + ", " + this.greeting;

    }

}

然后我们使用下面的函数定义 @required 和 @validate 装饰器:

import "reflect-metadata";

const requiredMetadataKey = Symbol("required");

function required(target: Object, propertyKey: string | symbol, parameterIndex: number) {

    let existingRequiredParameters: number[] = Reflect.getOwnMetadata(requiredMetadataKey, target, propertyKey) || [];

    existingRequiredParameters.push(parameterIndex);

    Reflect.defineMetadata(requiredMetadataKey, existingRequiredParameters, target, propertyKey);

}

function validate(target: any, propertyName: string, descriptor: TypedPropertyDescriptor<Function>) {

    let method = descriptor.value;

    descriptor.value = function () {

        let requiredParameters: number[] = Reflect.getOwnMetadata(requiredMetadataKey, target, propertyName);

        if (requiredParameters) {

            for (let parameterIndex of requiredParameters) {

                if (parameterIndex >= arguments.length || arguments[parameterIndex] === undefined) {

                    throw new Error("Missing required argument.");

                }

            }

        }

        return method.apply(this, arguments);

    }

}

@required装饰器添加了元数据实体把参数标记为必需的。 @validate装饰器把greet方法包裹在一个函数里在调用原先的函数前验证函数参数。

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

元数据

一些例子使用了reflect-metadata库来支持实验性的metadata API。 这个库还不是ECMAScript (JavaScript)标准的一部分。 然而,当装饰器被ECMAScript官方标准采纳后,这些扩展也将被推荐给ECMAScript以采纳。

你可以通过npm安装这个库:

npm i reflect-metadata --save

TypeScript支持为带有装饰器的声明生成元数据。 你需要在命令行或 tsconfig.json里启用emitDecoratorMetadata编译器选项。

Command Line:

tsc --target ES5 --experimentalDecorators --emitDecoratorMetadata

tsconfig.json:

{

    "compilerOptions": {

        "target": "ES5",

        "experimentalDecorators": true,

        "emitDecoratorMetadata": true

    }

}

当启用后,只要reflect-metadata库被引入了,设计阶段添加的类型信息可以在运行时使用。

如下例所示:

import "reflect-metadata";

class Point {

    x: number;

    y: number;

}

class Line {

    private _p0: Point;

    private _p1: Point;

    @validate

    set p0(value: Point) { this._p0 = value; }

    get p0() { return this._p0; }

    @validate

    set p1(value: Point) { this._p1 = value; }

    get p1() { return this._p1; }

}

function validate<T>(target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<T>) {

    let set = descriptor.set;

    descriptor.set = function (value: T) {

        let type = Reflect.getMetadata("design:type", target, propertyKey);

        if (!(value instanceof type)) {

            throw new TypeError("Invalid type.");

        }

        set(value);

    }

}

TypeScript编译器可以通过@Reflect.metadata装饰器注入设计阶段的类型信息。 你可以认为它相当于下面的TypeScript:

class Line {

    private _p0: Point;

    private _p1: Point;

    @validate

    @Reflect.metadata("design:type", Point)

    set p0(value: Point) { this._p0 = value; }

    get p0() { return this._p0; }

    @validate

    @Reflect.metadata("design:type", Point)

    set p1(value: Point) { this._p1 = value; }

    get p1() { return this._p1; }

}

注意  装饰器元数据是个实验性的特性并且可能在以后的版本中发生破坏性的改变(breaking changes)。

相关文章

  • TypeScript——装饰器(四)

    参数装饰器 参数装饰器声明在一个参数声明之前(紧靠着参数声明)。 参数装饰器应用于类构造函数或方法声明。 参数装饰...

  • TypeScript基础入门之装饰器(三)

    转载 TypeScript基础入门之装饰器(三) 继续上篇文章[TypeScript基础入门之装饰器(二)] 访...

  • TS装饰器初体验,用装饰器管理koa接口

    typescript中的装饰器有很多种,比如类装饰器、方法装饰器、属性装饰器等等,先看看装饰器的定义吧,下面以类装...

  • 如何配置React项目直接使用TypeScript包(babel

    上期我们说到了TypeScript装饰器(decorators)和JavaScript装饰器编译出的代码不同,我们...

  • 迁移React项目至TypeScript(babel版)

    上期我们说到了TypeScript装饰器(decorators)和JavaScript装饰器编译出的代码不同,虽然...

  • 【TypeScript】装饰器

    在看VSCODE源码的时候,看到这样一部分代码: 疑惑之际,查看一下官方文档:https://www.tslang...

  • TypeScript装饰器

    装饰器是一种特殊类型的声明,它可以用在类声明、方法、属性或者参数上。顾名思义,它是用来给附着的主体进行装饰,添加额...

  • Typescript装饰器

    装饰器主要用于将一些常用操作进行抽象出一层对类,方法,属性,参数进行修饰的函数。常用例子:设置属性时,打日志等。 ...

  • 装饰器 TypeScript

    装饰器 : 装饰器是一种特殊类型的声名 。它能够被附加到类声明,方法,属性或参数上 , 可以修改类的行为。 通俗的...

  • TypeScript 装饰器

    TypeScript 与 ES6 的装饰器? ES6 的装饰器是一种函数,写成@ + 函数名。它可以放在类和类方法...

网友评论

    本文标题:TypeScript——装饰器(四)

    本文链接:https://www.haomeiwen.com/subject/cvdxoctx.html