JavaScript – Why Injecting Data in a Class Constructor is Bad Practice

classdecoratorjavascripttypescript

I am reading the book "Learning TypeScript" by Remo Jansen. In one section the author describes how to create a very simple proof-of-concept MVC framework including how to create the Model class and says the following:

A model needs to be provided with the URL of the web service that it consumes. We are going to use a class decorator named ModelSettings to set the URL of the service to be consumed. We could inject the service URL via its constructor, but it is considered a bad practice to inject data (as opposed to a behavior) via a class constructor.

I don't understand that last sentence. In particular, I don't understand what it means to "inject data". It seems to me that in almost all introductions to JavaScript classes using over-simplified examples, data is introduced ("injected"?) into the constructor via its parameters. For example:

class Person {
  constructor(name) {
    this.name = name;
  }
}

I certainly think of name as data, not as behaviour, and it is universally included in this sort of example as a constructor parameter, and there is never any mention that this is bad practice. I thus assume I'm misunderstanding something in the above quote, either what is meant by "data" or by "inject" or something else.

Your answers could include explanations of when, where, how and why to use decorators in JavaScript/TypeScript, as I strongly suspect that concept is intimately connected to the understanding I seek. However, more importantly, I want to understand more generally what is meant by injecting data via a class constructor and why that's bad.


To give more context to the above quote, this is the situation: A Model class is created which, in this example, will be used to create stock exchange models, one for NASDAQ and one for NYSE. Each model requires the path of the web service or static data file that will provide the raw data. The book states that a decorator should be used for this information, rather than a constructor parameter, leading to the following:

@ModelSettings("./data/nasdaq.json")
class NasdaqModel extends Model implements IModel {
  constructor(metiator : IMediator) {
    super(metiator);
  }
...
}

I just haven't been understanding why I should add the service url via the decorator rather than simply as a parameter for the constructor, e.g.

constructor(metiator : IMediator, serviceUrl : string) {...

Best Answer

I'll give the author the benefit of the doubt and perhaps that is the way things are for Typescript, but otherwise in other environments that's a totally unsubstantiated claim that shouldn't be taken seriously.

Off the top of my head, I can think of a variety of situations where passing data via constructor is good, some that are neutral, but none where it's bad.

If a particular class depends on a particular piece of data in order to be in a valid state and run properly, it makes perfect sense to demand that data in the constructor. A class representing a serial port could take the port name, a file object could require the filename, a drawing canvas requiring its resolution, etc. Unless you pass the data in the constructor, it's possible you could have the object in an invalid state that has to be watched for and checked. Otherwise you can check only at object instantiation and afterwards assume its working for the most part. The authors claim makes that beneficial situation impossible.

Additionally, deciding to forbid passing data in a constructor also makes virtually all immutable objects impossible. Immutable objects have a variety of benefits in many situations, and all of those would be thrown out with the author's policy.

Even if mutable objects are what you want, how is this bad practice:

var blah = new Rectangle(x,y,width,height);

in favor of:

var blah = new Rectangle();
blah.X = x;
blah.Y = y;
blah.Width = width;
blah.Height = height;

Does the author really think the first is bad practice and I should always go with option 2? I think that's crazy talk.

So, since I don't have the book, and wouldn't read it anyway even if I did, I'd view that statement and pretty much any general statement in it at this point with a significant amount of suspicion.

Related Topic