1、修改tsconfig.json
"experimentalDecorators": true
"emitDecoratorMetadata": true,
向装饰器传递参数得使用工厂函数写法
四种装饰器返回值类型:
ClassDecorator
PropertyDecorator
MethodDecorator
ParameterDecorator
类中不同声明上的装饰器将按以下规定的顺序应用:
参数装饰器,然后依次是方法装饰器,访问符装饰器,或属性装饰器应用到每个实例成员。
参数装饰器,然后依次是方法装饰器,访问符装饰器,或属性装饰器应用到每个静态成员。
参数装饰器应用到构造函数。
类装饰器应用到类。
多个装饰器调用顺序:
当为普通函数时:从下往上
当为工厂函数时:先从上往下执行非返回的函数,然后从下往上执行返回的函数
2、使用
(1)类装饰器
(1)类装饰器表达式会在运行时当作函数被调用
类装饰器应用于类构造函数,可以用来监视,修改或替换类定义,类装饰器不能用在声明文件中( .d.ts),也不能用在任何外部上下文中(比如declare的类).
(2)接收一个参数,类的构造函数(类本身)作为其唯一的参数,参数.name返回类的名称。
(3)如果类装饰器返回一个值,它会使用提供的构造函数来替换类的声明。
即会用装饰器返回的类替换掉被装饰的类
(4)装饰器在类定义时被调用,而不是创建实例时
方式一:
泛型继承一个有着多个参数的返回任意类型的函数,即构造函数或类
function xx<T extends new (...args:any[])=>any>(constructor:T){
return class extends constructor{ 类扩展构造函数,只能修改,不能增加属性
增加/修改属性
类中声明的属性名=值,不需要this
增加方法
方法名(){
调用类属性需要this.属性名
}
类实例调用增加的方法需要(对象 as any).方法名(),否则报错,解决方法二
}
}
@xx
@xx2
class 类{
...
}
方式二:
function xx<T extends new (...args:any[])=>any>(constructor:T){
return class extends constructor{ //类扩展构造函数
属性和方法的增加修改
}
}
const XX=xx(class {
属性:类型,
属性2:类型2
constructor(参数:类型){
this.属性=name;
}
}
)
const x=new XX(参数);
xx.新增方法名();
工厂模式使用装饰器:
function xx(){
return xx<T extends new (...args:any[])=>any>(constructor:T){
return class extends constructor{ //类扩展构造函数
属性和方法的增加修改
}
}
}
const XX=xx()(class {
属性:类型,
属性2:类型2
constructor(参数:类型){
this.属性=name;
}
}
)
const x=new XX(参数);
xx.新增方法名();
(2)类的方法装饰器
它会被应用到方法的属性描述符上,可以用来监视,修改或者替换方法定义
1、方法装饰器返回一个属性描述符对象,会替代掉修饰的方法的属性描述符
function xx(target:any,propertyKey:string,descriptor:PropertyDescriptor)
{
return{
value:'xx',
enumerable:false
}
}
2、方法装饰器有三个参数
(1)静态方法来说是类的构造函数,普通方法是类的原型对象(prototype)。
(2)方法的名字。
(3)方法的属性描述符(value: [Function], writable: true,enumerable: true, configurable: true)。
function xx(target:any,propertyKey:string,descriptor:PropertyDescriptor)
{
descriptor.value就是该方法的引用
可以设置方法不可修改等操作
}
class X{
...
@xx
方法名(){
...
}
}
工程模式传递参数:
function xxx(msg:string){
function xx(target:any,propertyKey:string,descriptor:PropertyDescriptor)
{
descriptor.value就是该方法的引用
可以设置方法不可修改等操作
}
}
class X{
...
@xxx('错误提示')
方法名(){
...
}
}
(3)访问器装饰器(setter和getter)
在使用set和get之前调用,即类定义时
(1)该装饰器只能在get/set上使用一个,因为它联合了get和set访问器
(2)访问器装饰器返回一个属性描述符对象,会替代掉修饰的方法的属性描述符
function xx(target:any,propertyKey:string,descriptor:PropertyDescriptor)
{
return{
value:'xx',
enumerable:false
}
}
(3)访问器的三个参数
(1)静态方法来说是类的构造函数,普通方法是类的原型对象(prototype)。
(2)方法的名字。
(3)方法的属性描述符(set:func,get:func, writable: true,enumerable: true, configurable: true)。
function xx(target:any,propertyKey:string,descriptor:PropertyDescriptor)
{
...
}
class X{
..
get name(){
return this._name;
}
@xx
set name(name:string){
this._name=name;
}
}
(4)属性装饰器
给类的属性使用,用来监视类中是否声明了某个名字的属性。
有两个参数
(1)静态属性来说是类的构造函数,普通属性是类的原型对象(prototype)。
(2)属性的名字。
function xx(target:any,propertyKey:string):any
{
通过target[key]修改的是类原型上的属性,不是对象原型上的属性
如果要修改属性的访问修饰符,需要返回一个descriptor来替换原始的descriptor
const descriptor:PropertyDescriptor={
writable:false
}
return descriptor;
}
class Test{
@xx
name='xxx';
}
(5)参数装饰器
有三个参数
(1)静态属性来说是类的构造函数,普通属性是类的原型对象(prototype)。
(2)属性的名字。
(3)参数在函数参数列表中的索引。
使用:在需要装饰的参数前面放置
function xx(target:any,propertyKey:string,parameterIndex: number)
{
...
}
class X{
getInfo( 参数:类型,@xx 参数:类型){
...
}
}
代码示例:
类装饰器:
//类装饰器
//泛型继承一个多个参数的返回任意类型的函数,即构造函数
//泛型继承一个多个参数的返回任意类型的函数,即构造函数
function testDecorator<T extends new (...args:any[])=>any>(constructor:T){
return class extends constructor{ //类扩展构造函数
name='jacky'
name3='kacj'
getName()
{
console.log(this.name);
}
}
}
@testDecorator
class Test{
name:string;
name3:string;
constructor(name:string){
this.name=name;
}
}
const test =new Test('jeff');
console.log(test.name3);
(test as any).getName();
//装饰器装饰后的类
//泛型继承一个多个参数的返回任意类型的函数,即构造函数
function testDecorator(){
return function <T extends new (...args:any[])=>any>(constructor:T){
return class extends constructor{ //类扩展构造函数
name='jacky'
name3='kacj'
getName()
{
console.log(this.name);
}
}
}
}
// function testDecorator<T extends new (...args:any[])=>any>(constructor:T){
// return class extends constructor{ //类扩展构造函数
// name='jacky'
// name3='kacj'
// getName()
// {
// console.log(this.name);
// }
// }
// }
// const Test=testDecorator(class Test{
// name:string;
// name3:string;
// constructor(name:string){
// this.name=name;
// }
// }
// )
const Test=testDecorator()(class Test{
name:string;
name3:string;
constructor(name:string){
this.name=name;
}
}
)
const test =new Test('jeff');
console.log(test.name3);
方法装饰器:
/**
*
对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
成员的名字。
成员的属性描述符。
* @param key
*/
function nameDecorator(target:any,propertyKey:string,descriptor:PropertyDescriptor)
{
descriptor.value=function(){
return '修改了'
}
}
class Test{
name:string;
name3:string;
constructor(name:string){
this.name=name;
}
@nameDecorator
getName(){
return this.name;
}
}
const test =new Test('jeff');
console.log(test.getName())
//检测参数函数调用是否有问题实例
const userInfo:any=undefined;
function catchError(target:any,key:string,descriptor:PropertyDescriptor)
{
const fn=descriptor.value;
descriptor.value=function(){
try{
fn();
}catch(e)
{
console.log('userinfo有问题');
}
}
}
class Test {
@catchError
getName()
{
return userInfo.name;
}
getAge()
{
return userInfo.age;
}
}
const test = new Test();
test.getName();
访问器装饰器:
function visitDecorator(target:any,propertyKey:string,descriptor:PropertyDescriptor)
{
descriptor.get=function(){
console.log('修改了');
}
// console.log(descriptor.get);
}
class Test{
private _name:string;
constructor(name:string){
this._name=name;
}
get name(){
return this._name;
}
@visitDecorator
set name(name:string){
this._name=name;
}
}
const test =new Test('jeff');
// test.name='jeff shuai';
// console.log(test.name);
属性装饰器:
function nameDecorator(target:any,propertyKey:string):any
{
const descriptor:PropertyDescriptor={
writable:false
}
return descriptor;
}
class Test{
@nameDecorator
name='tom';
// constructor(name:string){
// this._name=name;
// }
}
const test =new Test();
// test.name='jacky'
console.log(test.name);
参数装饰器:
function arguementDecorator(target:any,propertyKey:string,parameterIndex: number)
{
console.log(parameterIndex);
}
class Test{
getInfo( name:string,@arguementDecorator age:number){
}
}
const test =new Test();
// test.name='jacky'
test.getInfo('jeff',30);