ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

TypeScript 装饰器

2020-09-17 12:00:21  阅读:182  来源: 互联网

标签:function TypeScript string 参数 属性 装饰 target


1. .装饰器的概念

  · 装饰器是一种特殊类型的声明,它能够被附加到类的声明,方法,访问符,属性或参数上;

  · 装饰器使用 @expression 这种形式,expression求值后必须为一个函数;

  · 它会在运行时被调用,被装饰的声明信息做为参数传入。

  · 装饰器执行时机是在代码编译时发生的(不是 TypeScript 编译,而是在 JavaScript 执行编译阶段)

启用装饰器特性,必须在命令行或 tsconfig.json 里启用 experimentalDecorators 编译器选项:

2. 装饰器语法

启用装饰器特性,必须在命令行或 tsconfig.json 里启用 experimentalDecorators 编译器选项:

// 在命令行中使用
tsc--target ES5--experimentalDecorators

// tsconfig.json 中开启:
{
    "compilerOptions": {
        "target": "ES5",
        "experimentalDecorators": true
    }
}

装饰器定义与应用举例:

// 装饰器定义
function sealed(target) {
    // do something with "target" ...
}
// 或使用装饰器工厂函数
function color(value: string) { // 这是一个装饰器工厂
    return function (target) { // 这是装饰器
        // do something with "target" and "value"...
    }
}

// 应用到一个声明上,例如:
@sealed @color let x: string;
// 或
@sealed
@color
let x: string

在 TypeScript 里,当多个装饰器应用在一个声明上时会进行如下步骤的操作:

  · 由上至下依次对装饰器表达式求值。

  · 求值的结果会被当作函数,由下至上依次调用。

多个装饰器应用在一个声明,举例:

// 多个装饰器应用在一个声明
function f() {
    console.log("f(): evaluated");
    return function (target, propertyKey: string) {
        console.log("f(): called");
    }
}
function g() {
    console.log("g(): evaluated");
    return function (target, propertyKey: string) {
        console.log("g(): called");
    }
}
class C {
    @f() @g() method() { }
}
// f(): evaluated
// g(): evaluated
// g(): called
// f(): called

3. 类装饰器

类中不同声明上的装饰器将按以下规定的顺序应用:

  · 有多个参数装饰器时:从最后一个参数依次向前执行。

  · 方法和方法参数中,参数装饰器先执行。

  · 方法和属性装饰器,谁在前面谁先执行。因为参数属于方法一部分,所以参数会挨着方法执行。

  · 类装饰器总是最后执行。

类装饰器在类声明之前被声明(紧靠着类声明)。

类装饰器应用于类构造函数,可以用来监视,修改或替换类定义。

// 类装饰符实例
function Path(path: string) {
    return function (target: Function) {
        !target.prototype.$Meta && (target.prototype.$Meta = {})
        target.prototype.$Meta.baseUrl = path;
    };
}

@Path('/hello')
class HelloService {
    [x: string]: any;
    constructor() { }
}

console.log(HelloService.prototype.$Meta);  // => { baseUrl: '/hello' }
let hello = new HelloService();
console.log(hello.$Meta)                    // => { baseUrl: '/hello' }

4. 方法装饰器

方法装饰器声明在一个方法的声明之前,可以用来监视,修改或者替换方法定义。

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

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

  · 成员的名字;

  · 成员的属性描述符;

  注意:如果代码输出目标版本小于ES5,属性描述符将会是 undefined,返回值会被忽略。 如果方法装饰器返回一个值,它会被用作方法的属性描述符。

方法装饰器,举例:

// 方法装饰符实例
function GET(alias: string) {
    return function (target, methodName: string, descriptor: PropertyDescriptor) {
        target._alias = alias;
    }
}

class HelloService {
    _alias: string;
    constructor() { }
    @GET("getMyName")
    getUser() { }
}
let hello = new HelloService();
console.log(hello._alias);  // => gtMyName

5. 访问装饰器

访问器装饰器声明在一个访问器的声明之前,可以用来监视,修改或替换一个访问器的定义。

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

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

  · 成员的名字;

  · 成员的属性描述符;

  注意:如果代码输出目标版本小于ES5,属性描述符将会是 undefined,返回值会被忽略。

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

  TypeScript 不允许同时装饰一个成员的get和set访问器;

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

访问装饰器,举例:

// 访问装饰器实例
function access(value: string) {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        !target.$Meta && (target.$Meta = {})
        target.$Meta[propertyKey] = `It's a ${value} method`
    };
}
class Point {
    private _x: number;
    private _y: number;
    constructor(x: number, y: number) {
        this._x = x;
        this._y = y;
    }
    @access('get')
    get x() { return this._x; }
    @access('set')
    set y(y: number) { this._y = y; }
}
let point = new Point(1, 2);
console.log(point['$Meta']);    // => { x: "It's a get method", y: "It's a set method" }

6. .属性装饰器

属性装饰器声明在一个属性声明之前。

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

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

  · 成员的名字。

  注意: 属性描述符不会做为参数传入属性装饰器,因为目前无法在定义一个原型对象的成员时描述一个实例属性,且无法监视或修改一个属性的初始化方法,因此,属性描述符只能用来监视类中是否声明了某个名字的属性。

属性装饰器,举例:

// 属性装饰符实例
function DefaultValue(value: string) {
    return function (target: any, propertyName: string) {
        target[propertyName] = value;
    }
}
class Hello {
    @DefaultValue("world")
    greeting: string;
}
console.log(new Hello().greeting);  // => world

7. 参数装饰器

参数装饰器声明在一个参数声明之前, 参数装饰器应用于类构造函数或方法声明。

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

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

  · 成员的名字;

  · 参数在函数参数列表中的索引;

  注意:

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

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

参数装饰器,举例:

// 参数装饰器实例
function PathParam(paramName: string) {
    return function (target, methodName: string, paramIndex: number) {
        !target.$Meta && (target.$Meta = {});
        target.$Meta[paramIndex] = paramName;
    }
}
class HelloService {
    constructor() { }
    getUser(
        @PathParam("the user's id")
        userId: string
    ) { }
}
console.log((<any>HelloService).prototype.$Meta);   // => { '0': "the user's id" }

 

标签:function,TypeScript,string,参数,属性,装饰,target
来源: https://www.cnblogs.com/JosephWong/p/13684327.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有