首页 > 其他分享 >[Typescript] Decorator - PropertyDecorator, ClassDecorator, MethodDecorator

[Typescript] Decorator - PropertyDecorator, ClassDecorator, MethodDecorator

时间:2022-11-20 18:14:47浏览次数:59  
标签:function MethodDecorator Typescript console log ClassDecorator descriptor Course

MethodDecorator

  • @Log(level): Console log message
  • @Pref: Mesure time
function Log(level: LoggingLevel): MethodDecorator {
  return (
    target: any,
    propertyKey: string | symbol,
    descriptor: PropertyDescriptor
  ) => {
    console.log("target", target);
    console.log("propertyKey", propertyKey);
    console.log("descriptor", descriptor);

    const originalFn = descriptor.value;
    // Cannot use arrow function
    descriptor.value = function (...args: any[]) {
      if (level <= appMaxLoggingLevel) {
        console.log(
          `>> Log: ${propertyKey.toString()}, ${JSON.stringify(args)}`
        );
      }
      originalFn.apply(this, args);
    };
  };
}

function Pref() {
  return (
    target: any,
    propertyKey: string | symbol,
    descriptor: PropertyDescriptor
  ) => {
    const originalFn = descriptor.value;
    descriptor.value = function (...args: any[]) {
      console.log(`started at ${new Date().getTime()}`);
      originalFn.apply(this, args);
      console.log(`ended at ${new Date().getTime()}`);
    };
  };
}

 

Usage:

enum LoggingLevel {
  ERROR,
  INFO,
  WARN,
  DEBUG,
  TRACE,
}

const appMaxLoggingLevel = LoggingLevel.WARN;

class DbService {
  // saveData function is wrapped in Log
  // Pref wrap both
  @Pref()
  @Log(LoggingLevel.INFO)
  saveData(data: any) {
    console.log(`saving data in the database...`);
  }
}

const db = new DbService();
db.saveData({ hello: "world" }); // >> Log: saveData, [{"hello":"world"}]

/*
target {}
propertyKey saveData
descriptor {
  value: [Function: saveData],
  writable: true,
  enumerable: false,
  configurable: true
}
started at 1668938096069
>> Log: saveData, [{"hello":"world"}]
saving data in the database...
ended at 1668938096069
*/

 

 ClassDecorator

  • SealClass: Cannot modify class & it's prototype
// @SealClass()
function SealClass(): ClassDecorator {
  return (constructor: Function) => {
    Object.seal(constructor);
    Object.seal(constructor.prototype);
  };
}

// @SealClass
// function SealClass(constructor: Function) {
//   Object.seal(constructor);
//   Object.seal(constructor.prototype);
// }

 

Usage:

@SealClass()
class DbService {
  // saveData function is wrapped in Log
  // Pref wrap both
  @Pref()
  @Log(LoggingLevel.INFO)
  saveData(data: any) {
    console.log(`saving data in the database...`);
  }
}

const db = new DbService();
// TypeError: Cannot define property sayHello, object is not extensible
Object.defineProperty(DbService, "sayHello", {
  value: () => {
    console.log("Should error");
  },
});

 

PropertyDecorator

  • @DatabaseId: auto generate id if not yet defined, otherwise return generated id 
function DatabaseId(): PropertyDecorator {
  return (classPrototype: any, propertyKey: string | symbol) => {
    Object.defineProperty(classPrototype, propertyKey, {
      get: function () {
        if (!this["_id"]) {
          this["_id"] =
            Date.now().toString(36) + Math.random().toString(36).slice(2);
        }
        return this["_id"];
      },
    });
  };
}

 

Usage:

class Course {
  @DatabaseId()
  id: string;

  title: string;

  constructor(title: string) {
    this.title = title;
  }

  print(message: string) {
    console.log(`${message}, Course ${this.title}, id ${this.id}`);
  }
}

const course1 = new Course("Typescript");
// Course 1 id:  lap621lv3gohkrz1ghf
console.log(`Course 1 id: `, course1.id);
// Course 1:  Course { title: 'Typescript', _id: 'lap621lv3gohkrz1ghf' }
console.log(`Course 1: `, course1);
const course2 = new Course("Angular");
// Course 2 id:  lap621lwisnfp23ubo
console.log(`Course 2 id: `, course2.id);
// Course 2:  Course { title: 'Angular', _id: 'lap621lwisnfp23ubo' }
console.log(`Course 2: `, course2);

 

 

----Full Code---

enum LoggingLevel {
  ERROR,
  INFO,
  WARN,
  DEBUG,
  TRACE,
}

function Log(level: LoggingLevel): MethodDecorator {
  return (
    target: any,
    propertyKey: string | symbol,
    descriptor: PropertyDescriptor
  ) => {
    console.log("target", target);
    console.log("propertyKey", propertyKey);
    console.log("descriptor", descriptor);

    const originalFn = descriptor.value;
    // Cannot use arrow function
    descriptor.value = function (...args: any[]) {
      if (level <= appMaxLoggingLevel) {
        console.log(
          `>> Log: ${propertyKey.toString()}, ${JSON.stringify(args)}`
        );
      }
      originalFn.apply(this, args);
    };
  };
}

function Pref() {
  return (
    target: any,
    propertyKey: string | symbol,
    descriptor: PropertyDescriptor
  ) => {
    const originalFn = descriptor.value;
    descriptor.value = function (...args: any[]) {
      console.log(`started at ${new Date().getTime()}`);
      originalFn.apply(this, args);
      console.log(`ended at ${new Date().getTime()}`);
    };
  };
}

// @SealClass()
function SealClass(): ClassDecorator {
  return (constructor: Function) => {
    Object.seal(constructor);
    Object.seal(constructor.prototype);
  };
}

// @SealClass
// function SealClass(constructor: Function) {
//   Object.seal(constructor);
//   Object.seal(constructor.prototype);
// }

function DatabaseId(): PropertyDecorator {
  return (classPrototype: any, propertyKey: string | symbol) => {
    Object.defineProperty(classPrototype, propertyKey, {
      get: function () {
        if (!this["_id"]) {
          this["_id"] =
            Date.now().toString(36) + Math.random().toString(36).slice(2);
        }
        return this["_id"];
      },
    });
  };
}

const appMaxLoggingLevel = LoggingLevel.WARN;

@SealClass()
class DbService {
  // saveData function is wrapped in Log
  // Pref wrap both
  @Pref()
  @Log(LoggingLevel.INFO)
  saveData(data: any) {
    console.log(`saving data in the database...`);
  }
}

class Course {
  @DatabaseId()
  id: string;

  title: string;

  constructor(title: string) {
    this.title = title;
  }

  print(message: string) {
    console.log(`${message}, Course ${this.title}, id ${this.id}`);
  }
}

const db = new DbService();
db.saveData({ hello: "world" }); // >> Log: saveData, [{"hello":"world"}]
/*
// TypeError: Cannot define property sayHello, object is not extensible
Object.defineProperty(DbService, "sayHello", {
  value: () => {
    console.log("Should error");
  },
});
*/
/////

const course1 = new Course("Typescript");
// Course 1 id:  lap621lv3gohkrz1ghf
console.log(`Course 1 id: `, course1.id);
// Course 1:  Course { title: 'Typescript', _id: 'lap621lv3gohkrz1ghf' }
console.log(`Course 1: `, course1);
const course2 = new Course("Angular");
// Course 2 id:  lap621lwisnfp23ubo
console.log(`Course 2 id: `, course2.id);
// Course 2:  Course { title: 'Angular', _id: 'lap621lwisnfp23ubo' }
console.log(`Course 2: `, course2);

 

标签:function,MethodDecorator,Typescript,console,log,ClassDecorator,descriptor,Course
From: https://www.cnblogs.com/Answer1215/p/16909103.html

相关文章

  • simpread-TypeScript DOM 类型的声明
    TSDOM类型的声明lib.dom.d.tsHTMLInputElement<inputtype="text"@change="handleChange"/>consthandleChange=(evt:Event)=>{console.log((evt.targe......
  • Vue XQTypeScriptFramework 使用
    说明XQTypeScriptFramework隶属于XQFramework下JS基础性框架部分XQFramework励志将开发将常用开发语音基础性框架统一汇总,为全站开发使用到的基础语法进行统一,拜......
  • [Typescript] 111. Hard - String Join
    Createatype-safestringjoinutilitywhichcanbeusedlikeso:consthyphenJoiner=join('-')constresult=hyphenJoiner('a','b','c');//='a-b-c'Or......
  • TypeScript 复习与进阶三部曲 (3) – TypeScript 类型体操
    前言在 第一部–把TypeScript当强类型语言使用 和 第二部– 把TypeScript当编程语言使用 后,我们几乎已经把TypeScript的招数学完了.第三部就要开始做练......
  • [Typescript] 110. Hard - Union to Tuple
    Implementatype, UnionToTuple,thatconvertsauniontoatuple.Asweknow,unionisanunorderedstructure,buttupleisanordered,whichimpliesthatwe......
  • TypeScript 函数重载
    TypeScript函数重载发布于2020-03-1717:53:05阅读 3.4K0 一、可爱又可恨的联合类型由于JavaScript是一个动态语言,我们通常会使用不同类型的参数来调用同......
  • TypeScript 4.9 发布,新增 satisfies 操作符
    TypeScript4.9发布,新增satisfies操作符来源:OSCHINA编辑: 罗奇奇2022-11-1707:04:50 1TypeScript4.9已正式发布,此版本引入了多项新功能。此版本......
  • [Typescript] noImplicitOverride
    Let'ssayyouextendsfromabaseclass,youintenttooverrideamethodinbaseclassclassBaseCmp{showCmp(){}hideCmp(){}helperMethod(){}}cla......
  • 【草稿】在 Typescript 中从对象中动态解构接口类型
    问题interfaceA{title:string,description:string,}leta={title:"titlea",description:"descriptiona",url:"http://example.com/a"}是......
  • React中常见的TypeScript定义实战
    一引沿Fiber架构是React16中引入的新概念,目的就是解决大型React应用卡顿,React在遍历更新每一个节点的时候都不是用的真实DOM,都是采用虚拟DOM,所以可以理解成fiber就是R......