We crunched the data from SonarLint to discover the top 5 most common TypeScript issues. In this 5 part series, we outline each issue and how to avoid it.
Take a look at the code below and have a think about what it does:
The name might suggest that it is going to perform some counting, but there’s a problem. The code doesn’t capture the object in a variable, so there’s no way it can be used to count anything. Or is there?
I can imagine two implementations for an object like this that is going to perform some counting. One might look like this:
In this case the class encapsulates the data, the current count, and its behaviour, the
increment method. If you just instantiate this object then nothing will happen and if, like in the first code example, you fail to capture the object as a variable you’ll never be able to use it. If this is the implementation of
Counter then just calling
new Counter() will create and immediately drop the object and you will achieve nothing.
To use this
Counter correctly the code should look like this:
So perhaps there is a different implementation? How about something like this:
new Counter() will perform an action, it will update the
counter variable that lives outside of the class. Class constructors should not be used to manipulate external state, it breaks the encapsulation of the data within the object. This
counter variable is a hidden state that makes it harder to reason about what the application is now doing.
Think back to the start of this post where we tried to imagine what the code would do. I would bet you did not think that instantiating an object would come with a side-effect like affecting this hidden state. And you should not! When you create an object, you should be worrying about the state within that object, not within the module in which it is written or within the entire global state of the application. If you don’t worry about the potential side-effects and classes like this exist, then you may introduce countless bugs into your application by messing around with that hidden state without meaning to.
All of this brings us to the TypeScript issue of the day: objects should not be created to be dropped immediately without being used. Either there was a mistake in the original code and the object should have been assigned to a variable, which is the most likely scenario, or the object constructor is causing side effects and that should be extracted from the constructor to a separate function that can be called directly. When code does this it is confusing, hard to read and hard to keep track of; a real code smell.
If you have SonarLint loaded up in your editor, you will be alerted of this TypeScript issue and you’ll never create and drop an object immediately by mistake again. SonarLint also provides some insight into what could go wrong with each issue it surfaces, useful if you want to learn more about the issue and why it might be a bad idea.