A unit-testable ES6 decorator convention

This, looks awesome:

@connectToState(state => state.someProperty)
@logClassWithArgs({ when : { name : β€œremo”} })
export class Person { 
  public name: string; 
  // …
}

But, as everyone who had tried to unit test a decorated class (in this case Person) would tell you, this is a pain to unit test. To be precise, it’s a pain to mock logClassWithArgs and connectToState and access the exported Person when you need to unit test Person.

What we need is to independently export all the decorations and the decorated component, for unit testing goodness. How about:

export const connector = connectToState(state => state.someProperty);

export const logger = logClassWithArgs({ when : { name : β€œremo”} });

export const DecoratedPerson = decorate(Person, connector, logger);

Now, we can test connector, logger and Person independently, without any mocking. But what’s that magical decorate function?

function decorate (Klass, ...decorations) {
  return _.reduce(
    decorations,
    (result, decorator) => {
      return decorator(result);
    },
    Klass
  );
}

We take our Klass (which could also be any class) and reducing all of the decorations, on top of Klass. This is exactly what happens when you @decorate.

Written on October 12, 2016