ES7 Decorators
I read a fantastic article the other day by Addy Osmani, who among other things created Yeoman, TodoMVC, Material Design Lite, and who works at Google on Chrome and Polymer. The article was what we can expect from ES7 Decorators, which can be found below:
You should definitely read the article because it is a succinct and clear explanation of decorators and what you would use them for. They are available to use now in both Babel, though not at the time of writing in Traceur. Generators along with other languages features like async/await, are major additions to JavaScript that should be coming along next year, so you should read up on them now! This article is just a quick summary of Addy’s with some different examples of what you can use decorators for.
You can check out the examples presented in this article in the online Babel REPL, as long as you check the “Experimental” checkbox. You can then run the generated result in something like JSFiddle.
So, what’s a decorator?
A decorator, put simply, is a function that can transparently wrap another function, class or property to provide extra functionality. Here’s what one might look like, from Addy’s article, a readonly
decorator that prevents a class property from being overridden.
// decorators.js
function readonly(target, key, descriptor) {
descriptor.writable = false;
return descriptor;
}
export default { readonly }
// person.js
import { readonly } from 'decorators';
class Martin {
@readonly
dateOfBirth = '1990-09-25';
}
The @readonly
declaration above the dateOfBirth
property is how you would use the decorator, which in this case I’ve defined in another file. Let’s have a look at what happens if we try and write to the property:
let me = new Martin();
me.dateOfBirth = new Date();
// Exception: Attempted to assign to readonly property
You can see that you get target
, key
and descriptor
method parameters in your decorator function. They each target different things and have their own properties:
target
– The class that the decorator is used on.key
– If using the decorator on a property, this is the name of the property.descriptor
– Contains the propertiesvalue
,enumerable
,configurable
, andwritable
for the property/function.
You can also define your decorator as a factory, so you can pass extra parameters into the decorator function. This can be used to do things like attach extra properties to a class. For example:
function gang(name, location) {
return function(target) {
target.name = name;
target.location = location;
}
}
@gang('The Warriors', 'Coney Island');
class Group() {}
@gang('The Riffs', 'Gramercy Park');
class Group() {}
@gang('Turnbull ACs', 'Gunhill');
class Group() {}
Thoughts
I don’t know about you but I’m getting really excited about using decorators. They remind me of Attributes in C#, which I’ve used a lot before when writing REST APIs in .NET. I think they have massive potential in large frontend applications to tightly implement security functionality. For example, if you don’t want someone making certain API calls via the frontend (you should also apply the same rules on the API) you could do something like this:
function adminOnly(user) {
return function(target) {
if (!user.isAdmin) {
toast.error('You do not have sufficient privileges for this area!');
return false;
}
}
}
@adminOnly(app.identity.currentUser)
function deleteAllUsers() {
app.api.users.delete().then((response) => {
toast.success('Yay you deleted everyone!');
});
}
Granted this is an extremely basic example that skips around things like Dependency Injection (if you’re using Angular) or ES6 import
statements. I’ll be writing an article where I explore how decorators can be used with Angular in the future. What’s more important is the recognition of the power that decorators bring to JavaScript, and that they are something you should be keeping an eye on as ES7 is developed further and comes closer to release.
If you thought ES6 was good, ES7 is really exciting! Check it out!