TypeScript 装饰器(decorators)

本文深入探讨TypeScript中的装饰器特性,包括其基本概念、如何启用、不同类型的装饰器(如类装饰器、属性装饰器、方法装饰器和参数装饰器)的使用方式及其内部工作机制。同时,还介绍了装饰器工厂的创建方法,以及装饰器在类、属性、方法和参数上的应用顺序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

介绍

类似与Java中的注解,可以用于类、域、以及方法或者方法的参数上。
在typescript中目前是一项实验性的特性,通过修改配置文件支持:

{
	"compilerOptions":{
		"experimentalDecorators": true
	}
}

装饰器使用

装饰器使用@expression这种形式,expression求值后必须为一个函数。也就是说,@后面可以接一个表达式,只需要这个表达式的值是一个函数即可。

所以我们可以这样定义装饰器:

function Controller(constructor: Function) {
	// 得到类的构造函数
}

@Controller
class User {}

当然这只是装饰器的一种形式,后面会给出装饰器用于类、方法、域、参数的不同形式及定义。

@expression的理解

既然expression是一个表达式,且这个表达式的值是一个函数,那么我可以想办法构造表达式啊。如下例:

function Controller(table: string) {
	// 得到类的构造函数
	reuturn function(constructor: Function){
		
	}
}

@Controller("user")
class User {}

在这个示例里面Controller(“user”)是一个函数调用表达式,返回值是一个函数,ok,满足要求。假设我们要将这个类对应到数据库的表,不就可以通过这种方式进行表名的注入了吗。

更高级一点的,我们可以构造装饰器工厂:

function decoratorFactory(...params){
	return function(target, property?,propertyDescriptor){
		
	}
}
@decoratorFactory('param')
class user{}

这样可以实现定制装饰器或者根据参数返回不同的装饰器

多个装饰器

@f @g x

装饰器的求职顺序是f(g(x))

同一个类的装饰器求值顺序

  1. 参数装饰器=》方法装饰器=》属性装饰器=》类装饰器
    总之就是范围从小到大

四类装饰器的使用

类装饰器

类装饰器应用于构造函数,可以用来监视、修改或替换类定义。类装饰器表达式会在运行时当作函数被调用,类的构造函数是唯一的参数。

function seal(constructor: Function) {
  console.log(constructor.name)
}

@seal
class Greeter1 {
}

如果类装饰器返回一个新的函数,那么会使用这个新的函数替换原有类的声明

属性装饰器

先看一个例子

function format(component:any, format?:string){
  console.log(component, format) // hello %s
  return function(target:any,propertyKey:string){
      Object.defineProperty(target,propertyKey,{
        get: function(){
          return '这是被拦截的消息'
        }
      })
      console.log(target,propertyKey)
  }
}
function seal(constructor: Function) {
  console.log(constructor.name)
}

@seal
class Greeter1 {
  @format('hello','%s')
  property = "property";
  hello: string = 'sub';
  constructor(m:string){
      this.hello = m;
  }
}

console.log(new Greeter('hello').property) // "这是被拦截的属性"

属性装饰器有两个参数

  • 对于实例属性,target是类的原型对象,对于静态成员是类的构造函数
  • 成员的名字

注:在上例中,我们使用Object.defineProperty来定义了原型对象的property属性,并给出的get/set方法,所以在子对象中定义property是无效的,所有实例访问的都是原型上的property属性,详情可参考https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty#%E7%BB%A7%E6%89%BF%E5%B1%9E%E6%80%A7

方法装饰器

和属性装饰器几乎完全相同,区别是方法装饰器可以有第三个参数,为属性的描述符对象

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

参数装饰器

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

  1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
  2. 成员的名字。
  3. 参数在函数参数列表中的索引。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值