patryk-developer
5/18/2018 - 8:24 AM

Dekoratory

Dekoratory w języku TypeScript zapewniają możliwość programowej ingerencji w proces definiowania klas. Trzeba pamiętać, że definicja klasy opisuje jej postać. Innymi słowy, definicja klasy określa, jakie dana klasa będzie mieć właściwości oraz metody. Z kolei te właściwości i metody stają się dostępne wyłącznie po utworzeniu instancji danej klasy.

//  Dekoratory
//  ==========


//  składnia dekoratorów
//  ================

function simpleDecorator(constructor : Function) {
  console.log('Wywołano funkcję simpleDecorator.');
}

@simpleDecorator
class ClassWithSimpleDecorator {
  
}

let instance_1 = new ClassWithSimpleDecorator();
let instance_2 = new ClassWithSimpleDecorator();

console.log(`instance_1 : ${instance_1}`);
console.log(`instance_2 : ${instance_2}`);


function secondDecorator(constructor : Function) {
  console.log('Wywołano funkcję secondDecorator.')
}

@simpleDecorator
@secondDecorator
class ClassWithMultipleDecorators {  
}

//  fabryki dekoratorów
//  ===================

function decoratorFactory(name: string) {
  return function (constructor : Function ) {
    console.log(`funkcja dekortora wywołana z parametrem : ${name}`);
  }
}

@decoratorFactory('nazwaTestowa')
class ClassWithDecoratorFactory {
}

//  parametry dekoratorów klas
//  ==========================

function classConstructorDec(constructor: Function) {
  console.log(`constructor : ${constructor}`);
  console.log(`constructor.name : ${(<any>constructor).name}`);
  constructor.prototype.testProperty = "wartość_testProperty";
}

@classConstructorDec
class ClassWithConstructor {
}

let classConstrInstance = new ClassWithConstructor();
console.log(`classConstrInstance.testProperty : ` 
  + `${(<any>classConstrInstance).testProperty}`);
  

//  dekoratory właściwości
//  ===================

function propertyDec(target: any, propertyKey : string) {
  console.log(`target: ${target}`);
  console.log(`target.constructor: ${target.constructor}`);
  console.log(`target.constructor.name: `
  + `${target.constructor.name}`);
  console.log(`propertyKey: ${propertyKey}`);
}

class ClassWithPropertyDec {
  @propertyDec
  name: string;
}


//function propertyDec(target: any, propertyKey : string) {
//  // console.log(`target : ${target}`);
//  // console.log(`target.constructor : ${target.constructor}`);
//  
//  if(typeof(target) === 'function') {
//    console.log(`nazwa klasy: ${target.name}`);
//  } else {
//    console.log(`nazwa klasy: ${target.constructor.name}`);    
//  }
//  
//  console.log(`propertyKey : ${propertyKey}`);
//}


//class ClassWithPropertyDec {
//  @propertyDec
//  propname: string;
//}

class StaticClassWithPropertyDec {
  @propertyDec
  static propname: string;
}


//  dekoratory metod
//  =================

function methodDec (target: any, 
  methodName: string, 
  descriptor?: PropertyDescriptor) {
    console.log(`target: ${target}`);
    console.log(`methodName: ${methodName}`);
    console.log(`target[methodName]: ${target[methodName]}`);
}

class ClassWithMethodDec {
  @methodDec
  print(output: string) {
    console.log(`Wywołano metodę ` 
      + `ClassWithMethodDec.print(${output}).`);
  }
}

//  stosowanie dekoratorów metod
//  =======================

function auditLogDec(target: any, 
  methodName: string, 
  descriptor?: PropertyDescriptor ) {
    
  let originalFunction = target[methodName];
  
  let auditFunction = function() {
    console.log(`auditLogDec: wywołano podmienioną ` 
      + `wersję metody ${methodName}. `);
    originalFunction.apply(this, arguments);
  }
  
  target[methodName] = auditFunction;
  return target;
}

class ClassWithAuditDec {
  @auditLogDec
  print(output: string) {
    console.log(`Wywołano metodę ` 
    + `ClassWithMethodDec.print(${output}).`);
  }
}

let auditClass = new ClassWithAuditDec();
auditClass.print("testy");


//  dekoratory parametrów
//  ====================


function parameterDec(target: any, 
  methodName : string, 
  parameterIndex: number) {
  
  console.log(`target: ${target}`);
  console.log(`methodName : ${methodName}`);
  console.log(`parameterIndex : ${parameterIndex}`);    
    
}

class ClassWithParamDec {
  print(@parameterDec  value: string) {
  }
}


//  metadane dekoratorów
//  ==================

// należy wykonać następujące polecenia: 
// npm install reflect-metadata --save
// npm install @types/reflect-metadata --save

import 'reflect-metadata';

function metadataParameterDec(target: any, 
  methodName : string, 
  parameterIndex: number) {

   let designType = Reflect.getMetadata(
     "design:type", target, methodName);
   console.log(`designType: ${designType}`)    
   
   let designParamTypes = Reflect.getMetadata(
     "design:paramtypes", target, methodName);
   console.log(`paramtypes : ${designParamTypes}`);
   
   let designReturnType = Reflect.getMetadata(
     "design:returntype", target, methodName);
   console.log(`returntypes : ${designReturnType}`);
}


class ClassWithMetaData {
  print( 
    @metadataParameterDec 
    id: number, 
    name: string) : number {
    return 1000;
  }
}
//*/