TypeScript: It's time to decorate your code 🎉
Tags: typescript, tutorial, functional, node
Published: 2020-03-12 05:17:19

Even though Decorators are still experimental (currently stage-2), let's figure out what they are, how we'd use them and whether it changes the way we think.  

>🚧 To enable experimental support for decorators, you must enable the `experimentalDecorators` compiler option in `tsconfig.json` or in the command line using `tsc --experimentalDecorators`.

So what is a Decorator?  A function that can be applied to a class, method, accessor, property or parameter.

🛑 Before we continue, know that there are two variations: Decorators and Decorator Factories

```typescript
// Oh look, a function, nothing special here as it just receives a `target` parameter
function basicDecorator(target) {
  // Decorator magic happens here
}

// A function that returns a function, still nothing special here!
function decoratorFactory(someValue: string) {
  return function(target) {
  // Decorator magic happens here
  }
}

// Usage
@basicDecorator
@decoratorFactory("some value")
class MyClass {
  //The expressions for each decorator are evaluated top-to-bottom.
  //The results are then called as functions from bottom-to-top.
}
```

## Topics
🎉 [Class Decorators](#class)
🎉 [Method Decorators](#method)
🎉 [Accessor Decorators](#accessor)
🎉 [Property Decorators](#property)
🎉 [Parameter Decorators](#parameter)

### <a name="class"></a>🎉 Class Decorators

Class decorators allow you to hook into the constructor of a class and allowing us to perform arbitrary code at runtime (before the class is executed/instantiated).

> 💀 You can change the prototype of the class (which is highly discouraged) so tread lightly!

```typescript
function sealed<T>(target: T) {
  Object.seal(target);
  Object.seal(target.prototype);
}

@sealed
class MyClass {
  // class code goes here
}
```

Would you rather see it all in action? Use the [Class Decorator Playground](https://codepen.io/johan-dutoit/pen/ExjoRRO).

### <a name="method"></a>🎉 Method Decorators

Method decorators allow us to completely override an existing method or better yet add some logic before it's executed (like deboucing, logging, etc.)

```typescript
// Method decorator
function myMethodDecorator(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
 // Update method descriptor, replace the method, etc.
}

class MyClass {
  @myMethodDecorator
  doAction() {
    // Do your thing here
    console.log("doAction has been called");
  }
}

```

Would you rather see it all in action? Use the [Method Decorator Playground](https://codepen.io/johan-dutoit/pen/rNVprmg).

### <a name="accessor"></a>🎉 Accessor Decorators

Unfortunately not many developers use Accessors enough (hopefully this entices you to get more familiar with them).  As with Method decorators, it allows us to modify the descriptor (which includes the getters and setters).

```typescript
function myAccessorDecorator(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  // Update method descriptor, replace the getter and/or setter, etc.
}

class MyClass {
  @myAccessorDecorator
  get myValue() {
    // internal set logic here
  }
}
```

Would you rather see it all in action? Use the [Accessor Decorator Playground](https://codepen.io/johan-dutoit/pen/ExjQZNz).


> 🛑 Hold up! The next two decorators are only really 'useful' when using external libraries like [reflect-metadata](https://rbuckton.github.io/reflect-metadata/) (which adds polyfills for the experimental metadata API), as they don't receive a property descriptor parameter.  Once decorators are fully supported, will the `reflect-metadata` library proposed for adoption.

### <a name="property"></a>🎉 Property Decorators

I'm sure you've picked up on the pattern already, simply add the decorator before the property.  If you're not going to use an external library, then I'd pass on using a property decorator and instead use an accessor or method decorator.

```typescript
function myPropertyDecorator(target: any, propertyKey: string) {
  // Use an external library like `reflect-metadata`
}

class MyClass {
  @myPropertyDecorator
  myValue: string;

  constructor(value: string) {
    this.myValue = value;
  }
}
```

Would you rather see it all in action? Use the [Property Decorator Playground](https://codepen.io/johan-dutoit/pen/NWqydOB).

### <a name="parameter"></a>🎉 Parameter Decorators

As before simply add the decorator before your parameter of choice.  You will notice that we have a new parameter called `parameterIndex`, which is pretty self explanatory. 

```typescript
function myParameterDecorator(target: any, propertyKey: string, parameterIndex: number) {
  // Use an external library like `reflect-metadata`
  console.log(...arguments);
}

class MyClass {
  doAction(value: string, @myParameterDecorator anotherValue: number) {
    console.log(`doAction called with: ${value} & ${anotherValue}`);
  }
}
```

Would you rather see it all in action? Use the [Parameter Decorator Playground](https://codepen.io/johan-dutoit/pen/bGdLqbm).



Proof read & edited by my beautiful wife ❤!

Remember to #KeepHavingFun