📜 ⬆️ ⬇️

Decorators in typescript: weapon versus complexity or useless whistle?

You, probably, have already heard about such a strange thing for a js / ts developer, like decorators . In general, this is a design pattern that can be used in any language. But some programming languages, such as python, dragged this pattern into their syntax, which caused a controversial reaction among developers. TypeScript has already established itself as forty, pulling a good syntax from different programming languages. But will decorators benefit him?


Today I will show you a whole factory and one great case study using decorators from our new SDK.

Let's see what we really need decorators for:




You can also discuss anti-cases using decorators for a long time, but let's leave it for later. Now we will focus on demonstrating the positive possibilities of decorators.
')
Probably every js developer, even the smallest, would like to see a nice enterprise debugging. Yes, so that you can request from the user who broke everything, a large and curly log. So meet: tracing on decorators.

For today's recipe, you need to update tsconfig.json :

// tsconfig.json { "compilerOptions": { "target": "ES5", "experimentalDecorators": true } } 

In general, that's all. You can do magic with decorators!
But you can not just take and write a trace with decorators alone. Let's write the trace function.

The first trace function on js, which I wrote at the very beginning of my career, used alert (). But this is against common sense. Let's look at the trace function that I offer you now.

 //   .      trace //      class TraceExperiment{ private isTrace: boolean = true; //        ,   //  . ,      ,  //   ,     function traceMe(functionName: string, parameters: string, result: string): void { if (this.isTrace) console.log( new Date().toString() + ` TRACE: ${functionName}(${parameters}) => ${result}`); } //          function doWork(param_one: any, param_two: any): any{ let result:any; //      this.traceMe(arguments.callee.name,arguments.join(),result); } 

We had to pull the heavy argument twice, and still have to make sure that no one took the function output from the tracer. Difficult and sad. Especially if you have to maintain and maintain this for a long time. I am sure that such decisions were written or supported by everyone.

Here, we have a delightful logger and some kind of improper, heavy use of it.

If you would like to:

  1. Include the tracer in a function in one line
  2. Have a guaranteed receipt of the arguments and the result of the function
  3. To achieve maximum resiliency
  4. Have the ability to transfer individual parameters at the declaration


This is where it's time to use decorators, which are given to us by typescript, and which will soon be available in javascript from the box:

  @Logger.trace("MODULE1") function doWork(param_one: any, param_two: any): any { //      } 


Yes, so simple. This is an example of using a decorator factory, almost like from a new version of our web sdk. I use the parameter in brackets to group output by modules. How such a factory looks like:

 //   public static trace(category:string) { //          // //   //     // propertyKey -    // descriptor -    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { return { //    .    //   ,       value: function (...args: any[]) { //      let params = ""; //   ,       try { params = args.map(a => JSON.stringify(a)).join(); } catch (e) { params = "[circular structure]"; } //   ,    // ,      let result = descriptor.value.apply(this, args); let r; //   ,       try { r = JSON.stringify(result); } catch (e) { r = "[circular structure]"; } //      Logger.traceMe(propertyKey, params, r); //   ,     return result; } }; } } 


After the conversion, the code of the function being decorated will be wrapped in the designer of the decorators:

  __decorate([Logger_1.LogManager.d_trace(Logger_1.LogCategory.RTC)], SeriousModule.prototype, "doWork", null); 


Even in converted form, the code looks neat and nice. As you can see, Python has shown us that decorators may not be an anti-development pattern, but a useful tool for dealing with complexity. They increase the readability of the code and allow you to "remove" the behavior of the function, while not complicating the readability. But, like any tool, decorators work well only for their intended purpose. If you get carried away and start using them right and left, it is easy to get an unreadable code with a dozen function decorators. Hopefully this won't happen with JavaScript and TypeScript.

As an illustration, we used a fragment of the cover of the book “Myself Decorator” Makhmutova Kh. I. “Eksmo Publishing House”

Source: https://habr.com/ru/post/277847/


All Articles