AngularDeveloper97
4 min readJun 25, 2018
At end of this article, you will be able to write your own decorators!

So you create an awesome angular component, and like me you can’t wait for people to start using it! But one thing is slightly troubling you, how do you ensure consumers of your component do so in an expected way. In this article we will discuss various ways to validate your component is being used as intended, we will be primarily focussing on the component Inputs.

Imagine a component where the input names are not representative enough of what data type they might be. This could cause the consumer to provide us with data we are not expecting, or the consumer forgets an input we are relying on internally. In either cases we would like to show an error, or throw an exception depending on the importance of the input in question. This is something typescript sadly cannot enforce because angular components are used in HTML templates. So we will be validating the inputs runtime.

We will start by building a simple component that will be displaying a users name and an age.

How would we go about validating the provided name is actually a string? We could do so using typescript getters and setters! This is super easy to do with the latest version of vscode ( V1.23.1 as of writing )

Okay now we have our getters and setters, we want to check if the value is actually a string. We can do this in the setter!

This does exactly what we need, but our one line of code input just turned into 11, and we are only validating one input. This can pollute our class members declarations pretty fast, and we also cannot check if the input value is ever set or not. As the setter only fires when… a value is set.

Meet ngOnChanges

ngOnChanges is a super useful hook that according to the documentation does the following

Lifecycle hook that is called when any data-bound property of a directive changes.

So how would we go on validating whether a given input is for example of a certain type.

Try changing the age, it will throw an error

That does exactly what we need, but our code is assuming the name property will always be there when the component inputs change. Which is not the case incase a different input was changed. So we will need to do safety checks before accessing currentValue

Changing the age now doesn’t cause exceptions.

We have now effectively almost reduced our amount of lines in half! But for every input we now have to write 6 lines of code to verify its the value we expect, different components will still need to write validation logic themselves, and we still don’t have a way of checking if an Input is initially set or not. We can do better.

Meet Typescript Decorators

We can use decorators on the class members we want to validate in different ways, this approach is not only more DRY but will help us keep the validation logic centralised which has pros like only enabling validation during development mode.

According to typescript a decorator is the following:

A Decorator is a special kind of declaration that can be attached to a class declaration, method, accessor, property, or parameter. Decorators use the form @expression, where expression must evaluate to a function that will be called at runtime with information about the decorated declaration.

Thats quite a mouthful, but decorators to me are basically fancy annotations that extend somethings functionality. So how would we for example control if a given Input is initially set? Or actually a better question would be, when do you actually check if a given Input is set? The OnInit lifecycle hook would be the perfect place to do so, our not so re-usable code would basically look like this.

We can make this re-usable by creating a decorator that will modify the constructed object’s implementation, more specifically the ngOnInit method.

That is what our decorator will look like, we will be decorating class members which we are expecting to be defined (not null or undefined to be precise). Our decorator will be passed two parameters, target and prop. target will represent the class ‘s prototype, and prop will represent the property name that is being decorated. With these two we can extend the ngOnInit of this instance, with Object.defineProperty we are creating a new property on this prototype, and inside the value function we are using this to refer to the class that had a member decorated by our isRequired. At the bottom we are calling the original ngOnInit with the right context using call to ensure any additional code that was originally in the ngOnInit is executed. When we decorate our inputs with the isRequired decorator, the final result is a console.error whenever we haven’t provided the component with the inputs it expects ! 🎉

This article winded up being a little bit bigger than I anticipated, so instead of showing how you would validate inputs against data types. I want you to give it a try! Try creating a decorator that checks whether the age is a number or not, I will be writing a follow up article explaining how to do it soon.