TypeScript 装饰器的基本语法

1,432 阅读4分钟

相信大家一定在很多代码中见过这样的用法:

对,没错像 @classDecorator 、****@propertyDecorator 这样子的语法就是装饰器。

装饰器是什么

要解释装饰器是什么,这里引用官方文档中一句话:

Decorators provide a way to add both annotations and a meta-programming syntax for class declarations and members

装饰器就是一种为类和类的成员添加注解或者实现元数据编程的语法

来看个具体的例子,在这个例子中 @classDecorator 就是一个类的装饰器:

可以看出:装饰器本质很简单,它就是一个函数,加上**@**符号,被应用到一些特定的目标上,就实现一个装饰器。

装饰器仅在解释执行时运行一次。

Decorators will be called at runtime with information about the decorated declaration.

装饰器工厂

说到这里,需简单介绍一下另一种非常常见的创建装饰器的方式:装饰器工厂(Decorator Factories)

这个时候,我们添加装饰器的时候不再是 @classDecorator 而是执行了这个函数 @classDecorator()

函数执行返回的函数才是真正的装饰器本身。

这种用法多用于装饰器需要根据用户传参来表现出不同的能力的场景。

If we want to customize how a decorator is applied to a declaration, we can write a decorator factory.

当然也有同学会单纯的喜欢这样的写法。

TypeScript 中有哪些装饰器

在 TypeScript 中,可以实现以下五种装饰器:类装饰器、方法装饰器、属性装饰器、访问器装饰器、参数装饰器

类装饰器

类装饰器声明于类之前

类装饰器仅有一个参数

  • 类的构造器(Player

返回值:可以返回一个类来替代你所装饰的类(可选)。例如:

这样一来,所有的 Player 其实已经变成了 Swimmer。当你 new Player() 得到其实是 Swimmer ,不过在 TS 的类型系统中存在一个问题,它并不会帮你识别这个实例是 Swimmer 类型。详见这里

方法装饰器

方法装饰器声明于类的方法之前,包括实例方法静态方法

方法装饰器有三个参数

  • 如果是静态方法就是类的构造器(Player),如果是实例方法就是类的原型(Player.prototype

  • 函数名

  • 函数的属性描述符

返回值:可以将其属性描述符返回(可选)

属性装饰器

属性装饰器申明于类的属性之前,包括实例属性静态属性

属性装饰器有两个参数

  • 如果是静态方法就是类的构造器(Player),如果是实例方法就是类的原型(Player.prototype
  • 属性名

返回值:Void

访问器装饰器

访问器装饰器申明于类的访问器(get/set)之前,包括实例访问器静态访问器

访问器装饰器有三个参数

  • 如果是静态方法就是类的构造器(Player),如果是实例方法就是类的原型(Player.prototype

  • 属性名

  • 访问器属性的属性描述符

返回值:可以将其属性描述符返回(可选)

注意:对于同一个属性来讲,不能同时在 get/set 上都是用装饰器,只需要选择一个即可

参数装饰器

参数装饰器申明于类方法的参数之前,包括实例方法静态方法

参数装饰器有三个参数

  • 如果是静态方法就是类的构造器(Player),如果是实例方法就是类的原型(Player.prototype

  • 参数名

  • 参数是函数参数列表的第几个

返回值:Void

多种装饰器的执行顺序

在了解了所有的装饰器类型后,这里存在的一个问题就是:如果多种装饰器被任意组合在一起,执行顺序是怎么的呢?我们直接来看一个例子:

为了方便我们自定义输出信息,这里全部使用了装饰器工厂的实现,例如:

这个包含了所有类型装饰器的例子,其执行结果如下:

更多的相关内容可以参考官方文档

对同一个属性的装饰器组合

对于同一个属性,TypeScript 允许我们为它应用多个装饰器,就像这样:

其执行顺序为:

可以看出,装饰器本身是按照距离被装饰目标从近到远的顺序执行的,等同于 f(g(getValue()))

如果使用的是装饰器工厂的话,像这样

其执行顺序为:

更多的相关内容可以参考官方文档

总结

这篇文档的主要目的就是想要说明 TypeScript 的装饰器语法是什么样子的,以及需要注意的事项,希望能够帮助大家在使用的时候,上手快一点,不要踩坑。

至于装饰器为什么会是这样个样子,以及在很多场景下的典型应用,后续通过其他的文章分享给大家。

参考