TS 装饰器

在了解nest js之前,要先对装饰器有进一步的认识。装饰器并不是ts所提供的特性,而是ts实现的ECMAScript提案。

为什么需要装饰器?基于装饰器我们能够快速优雅的复用逻辑,提供注释一样的解释说明效果,以及对业务代码能力的增强。同时,依赖注入也可以通过装饰器来简洁的实现。

1. 不同的装饰器

类装饰器

function addProp(construtor: Function){
	function.prototype.job = 'fe';
}

// 这里的函数就是一个装饰器,参数为被装饰的类的构造函数
@addPropp
class P{
	job: string;
	constructor(public name: string){};
}

let p = new p('ponny');
console.log(p.job); // 'fe'
function addProp(param: string): ClassDerector {
	return (constructor: Function) => {
		constructor.prototype.job = param;
	}
}

// 这里的函数接受一个参数,并返回一个装饰器
@addProp('fefb')
class P{
	job: string;
	constructor(public name: string){};
}

let p = new p('ponny');
console.log(p.job); // 'fefb'

方法装饰器

function addProps(): MesthidDesrector{
	return (taregt, properrtykey, descriptor) => {
		cnsole.log(target); // 类原型对象
		console.log(propertyKey); //修饰的方法
		console.log(descriptor); // 改方法的属性描述符
		
		descriptor.writable = false;
	}
}

class A{
	@addProp()
	originMethod() { 
		console.log('Originnal'); 
	}
}

const a = new A();
a.originMethod = () => { cosnole.log(changed!); }

a.originMethod(); // 'OrigiMethod'  ,这是装饰器的作用

函数addProp()返回一个方法装饰器,第三个参数descriptor有: writeable, enumerable, configurable

属性装饰器

function addProp(): PropertyDecoretor {
	retun (trget, propertyKey) => {
		console.log(propertyKey);
	};
}

class A {
	@addProp()
	originProps: any;
}

参数装饰器

function paramDeco(params?:any): ParameterDecorator {
	return (target, propertyKey, index) {
		conole.log(target);
		console.log(propertyKey);
		console.log(index);
		
		target.constructor.prototype.fromParamDeco = test';
	};
}

class B {
	someMethod(@parmaDeco param1: any, @paramDeco param2: any){
		console.log(param1,param2);
	}
}

new B().someMethod();
console.log(B.prototype.fromParamDecoretor);

2. 装饰器工厂
如果我们同时需要上面四种装饰器,可以考虑接入装饰器工厂,使用一个装饰器工厂来为我们根据条件吐出不同的装饰器来。

首先准备好各个装饰器函数,最好不要把功能写在里面,避免造成耦合

function classDeco(): ClassDecorator {
  return (target: Object) => {
    console.log('Class Decorator Invoked');
    console.log(target);
  };
}

function propDeco(): PropertyDecorator {
  return (target: Object, propertyKey: string) => {
    console.log('Property Decorator Invoked');
    console.log(propertyKey);
  };
}

function methodDeco(): MethodDecorator {
  return (
    target: Object,
    propertyKey: string,
    descriptor: PropertyDescriptor
  ) => {
    console.log('Method Decorator Invoked');
    console.log(propertyKey);
  };
}

function paramDeco(): ParameterDecorator {
  return (target: Object, propertyKey: string, index: number) => {
    console.log('Param Decorator Invoked');
    console.log(propertyKey);
    console.log(index);
  };
}

接着实现一个工厂函数,使得根据不同的条件/情况返回不同的装饰器

enum DecorateType {
	CLASS = 'class';
	METHOD = 'method';
	PROPERTY = 'property';
	PARAM = 'param';
}

type FactoryReturnType = 
	| ClassDecorater
	| MethodDecorator
	| Propertydecorator
	| ParamDecorator;
	
function decoFactory(type: DecoratorTytpe, ...argss:any[]): FactotyReturetype {
	switch(type) {
		case DecorateType.CLASS:
			return classDeco.apply(this, args);
		case DecoratorType.METHOD:
			return methodDeco.apply(this, args);
		case DecoratorType.PROPERTY: 
			return propertyDeco.apply(this, args);
		case DecoratorType.PARAM:
			return propertyDeco.apply(this, args);
		
		default:
			throw new Error('invlaid decorator type');
	}
}

@decoFactory(DecoratorType.CLASS)
class C {
  @decoFactory(DecoratorType.PROPERTY)
  prop: any;

  @decoFactory(DecoratorType.METHOD)
  method(@decoFactory(DecoratorType.PARAM) param: string) {}
}

3. 多个装饰器的应用顺序:

4. 多个装饰器来装饰同一个声明

function foo() {
    console.log("foo in");
    return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
        console.log("foo out");
    }
}

function bar() {
    console.log("bar in");
    return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
        console.log("bar out");
    }
}

class A {
    @foo()
    @bar()
    method() {}
}

// foo in
// bar in
// bar out
// foo out
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值