Photo by Alex Loup on Unsplash

A simple explanation of decorators in Javascript

Richard Oliver Bray
Octopus Labs London
5 min readApr 26, 2018

--

For those who have been using Angular 2 + you’ll be very familiar with decorators in Javascript.

@Component({   
selector: 'example-component',
template: '<div>Woo a component!</div>',
})

And for those who have been using Python (or other languages that support this), you’ll be very familiar with decorators in general.

def new_decorator(func):
def wrap_func():
print("Hello")
func()

return wrap_func

@new_decorator
def func_needs_decorator():
print("World")

func_needs_decorator()
# This prints:
# Hello
# World

But what are decorators and why as a frontend web developer would I ever need to use them?

What are decorators?

Decorators are a way of running a function or method inside another. The decorator, usually represented with an @ symbol is place above the function it manipulates, that function is passed into the decorator.

There are already ways to do this in JS but that becomes a bit messy and it doesn’t look very DRY if you want to use the function for multiple other functions or methods.

For Javascript currently you can only use decorators with classes, either in a class method or over the whole class, and you’ll also need to use Babel to transpile it as they are not currently supported in all browsers. Let’s go through how you’d actually set one up in a project.

How to use them in your project

To get started you’ll need to install a few key packages. If you’re using Webpack you’ll need;

I’m not sure what other module loaders will need so I’ll leave that up to you if you’re using something like Parcel. And you’ll need these for the actual transpilation;

This isn’t a tutorial on how to use Webpack, if you’re looking for that–I’ve got you covered. I’ll share what my final webpack.config.js file looks like so you get an idea of how to set yours up.

Note, I’ve used babel-preset-es2016 but es2015 should work just fine.

Okay, with that done you should all be set to go.

On line 5 of my webpack file I reference index.js and in that file I have replicated the js decorator example I wrote at the beginning of this post that didn’t work. Here is what the working version looks like.

I’ll do my best to explain this. As mentioned before decorators currently only work in javascript classes either manipulating a class method or the whole class. So like 9–14 is just that. A lot more syntax I know :(

Line 16 and 18 should be pretty self explanatory. And of course, line 1–7 is where the decorator function outside the class is actually created.

A decorator function takes in 3 parameters; target, name and descriptor. My example doesn’t use the first two but they are there for explanation reasons only.

Target — is the class the property is part of, so in my example that will return the People class with all it’s constructors and methods if it has any.

Name — the name of the property the decorator is modifying, in my case that would be “bob”.

Descriptor — the object that would have been passed or the thing you’ll use most from a decorator. In the case of my example it returns;

{
"value": bob() // function
"writable": true,
"enumerable": false,
"configurable": true
}
  • value: property that was passed into the decorator
  • writable: if the property is writable/read-only
  • enumerable: property can be included and visited in a loop
  • configurable: if the property can be configured

So back to the code. On line 2 I put the descriptor value (which is “Bob”) in a variable called oldValue. In line 3–5 I change the descriptor value with an anonymous function since, the value itself is a function, and in line 4 I use manipulate value with a string literal. Then in line 6 I return descriptor. An object needs to be returned in a decorator or it won’t work.

And that’s pretty much it.

Should I use decorators now?

Well in my opinion it’s not worth it if you’re planning to add less than 10 decorators.

Here’s what it looks like transpiled in babel.

So yeah a lot of code gets added, most of which is from ‘babel-plugin-transform-decorators-legacy’ but it’s good to know this before proceeding. The small amount of plugin code would make sense with 20 or 30 plus decorators, but if you used it only a single number of times in your code I don’t think it’s worth it considering you could do something like this;

In regular javascript which would use a lot less code.

Final thoughts

You’ll notice I haven’t talked much about decorators used on the whole class only decorators used on class methods and that’s purely subjective. I just don’t think class decorators will be as useful as method ones. Yes in React if you’re using Redux instead of doing something like this;

export default connect(mapStateToProps, mapDispatchToProps)(Homepage;

you could place this right above the class;

@connect(mapStateToProps, mapDispatchToProps)

but that’s not a massive win in terms of syntax reduction which is the main benefit of decorators in my opinion, that and readability.

Checkout my Github file with the above example → https://github.com/RichardBray/es-decorators

Sources

--

--

Richard Oliver Bray
Octopus Labs London

Co-founder of orva.studio. Building digital products and teaching others to do the same. Saved by grace.