Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
September 29, 2021 08:57 am GMT

Understanding TypeScript decorators.

JavaScript is an awesome programming language. And TypeScript has done a great job at filling in the gaps of JavaScript. Not only does it add types, it also implements a few extra features which aren't there in JavaScript yet. One of them are decorators.

What is a decorator?

Decorators have been there in programming languages for a long time. Definitions vary, but in short a decorator is a pattern in JavaScript which is used to wrap something to change it's behavior.

In both JavaScript and TypeScript this is an experimental feature. In JavaScript, it's still a Stage 2 proposal and you can only use it via transpilers like Babel.

I've decided to explain TypeScript decorators because in TypeScript it has been standardized, and both are basically the same anyways.

Using Decorators

This is a very simple example of how to use a decorator:

const myDecorator = (thing: Function) => {    // return something}@myDecoratorclass Thing {}

First we define a function myDecorator, and then we "decorate" a variable (our class Thing in this case) with the decorator. The decorator can return pretty much anything, but most of the time it used to set properties on the class, etc. Here's a real life sample:

const defaultGun = (gun: Function) => class extends gun {    ammo = 10}@defaultGunclass Gun {}

Now, Gun will have a ammo property by default.

const gun = new Gun()console.log(car.ammo) // => 10

Decorating functions

Another place we can use decorators is in class methods. This time, the decorator gets three arguments.

const myDecorator = (parent: Function, prop: string, descriptor: PropertyDescriptor) => {    // return something}class Gun {    @myDecorator    fire() {        console.log('Firing in 3... 2... 1... ')    }}

The first param contains the class where the decorated thing exists (in our case Gun). The second param is the name of the property decorated (in our case fire). The last is the property descriptor, which is the output of Object.getOwnPropertyDescriptor(parent[prop])

Properties

You can also decorate properties. It is pretty much the same as function decorators, except there is no third parameter:

const myDecorator = (parent: Function, prop: string) => {    // return something}

More places to decorate

You can also decorate in more places. Check out the documentation to learn more.

Use cases

There are many uses for decorators. We'll go over some here.

Calculate performance

class Gun {    @time    fire() {        console.log('Firing in 3... 2... 1... ')    }}

time could be a function which calculates the execution time.

Decorator factory

Decorators can also be factories, which returns a function which is the actual decorator. This can be useful when you want your decorators need any arguments.

// The decorator factoryconst change = value => {    // The factory will return a new handler    return (target, prop) => {        // We replace the old value with a new one        Object.defineProperty(target, prop, {value})    }}

Then when "decorating" we just need to decorate like a function:

class Gun {    @change(20)    ammo = 10}const gun = new Gun();console.log(gun.ammo) // => 20

A practical example: error handling

Let's use what we have learned to solve a real world problem.

class Gun {    ammo = 0    fire() {        console.log('Firing in 3... 2... 1... ')    }}

Let's assume that to fire, we need at least 1 ammo. We can make a check for that using a decorator:

const minAmmo = (ammo: number) => (    target: Object,    prop: string,    descriptor: PropertyDescriptor) => {    const original = descriptor.value;    descriptor.value = function (...args) {        if (this.ammo >= ammo) original.apply(this);        else console.log('Not enough ammo!');    }    return descriptor;}

minAmmo is a factory decorator which takes a parameter ammo which is the minimum ammo needed.

We can use implement it in our Gun class.

class Gun {    ammo = 0    @minAmmo(2)    fireTwice() {        console.log('Firing in 3... 2... 1... ')    }}

Now if you run fire(), it won't fire because we don't have enough ammo.

The nice thing is that we can just reuse this without rewriting an if statement. Suppose we need a fireOnce method. We can easily implement that.

class Gun {    ammo = 0    @minAmmo(2)    fireTwice() {        console.log('Firing twice in 3... 2... 1... ')    }    @minAmmo(1)    fireOnce() {        console.log('Firing once in 3... 2... 1... ')    }}

This kind of decorator can be really useful authentication. authorization, and all the other good stuff.

Liked the post? it. Loved it? it.

If you want more people to learn about this, share this on Twitter


Original Link: https://dev.to/siddharthshyniben/understanding-typescript-decorators-3ifc

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To