Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

plain objects VS class instances for model objects

What is the best practice for creating model objects in Angular / TypeScript:

  1. Should I use type annotation with object notation (objects are plain instances of Object)? E.g. let m: MyModel = { name: 'foo' }

  2. Should I use the new operator (objects are instances of the respective prototype)?

  3. Should these two approaches be mixed up and used situationally? (E.g plain objects, when receiving a response from the HttpClient, but new MyModel('foobar') for convenience to create instances by passing properties as constructor arguments)

Background of this question

I'm new to TypeScript and like many other developers I come from popular object oriented languages like Java.

A core concept I understood is that type annotations in TypeScript don't play a role at runtime. They are important for the compiler and for your editor's auto completion. Basically it's ECMAScript with the addition of compile time type checks.

At the time I didn't know this and expected TypeScript to be some kind of "client side Java", I found this Angular bug report: https://github.com/angular/angular/issues/20770

People (who don't understand TypeScript's type concept) complain about the HttpClient not converting the returned plain object to their model class type. Other people are defending this behavior and point out that there are no runtime types in JavaScript.

And here arises my problem: In fact there ARE runtime types in JavaScript. You can create instances of prototypes with the new operator and even check their constructor with the instanceof operator.

In TypeScript you have two ways for creating an instance:

1) Use the object notation (as they show in the Angular tutorial):

hero: Hero = {
  id: 1,
  name: 'Windstorm'
};

2) Use the new-operator:

hero: Hero = new Hero();

At the moment I'm working on a project where these two options are mixed up. I.e. model objects of the same type are instances of Object in some cases and instances of Hero in other cases.

I expect this leading to problems later, because the constructor is only called in the latter case.

My idea for a rule / best practice was to define all model instances as plain objects and to use the constructor for services, components etc. that are created by dependency injection. As a result I wouldn't use the new operator at all.

However I'm not sure if this is a good idea and I couldn't find a best practice recommendation about it.

EDIT

Important note for close voters: I'm not looking for your personal opionion here. I'm rather looking for some kind of officially documented Angular best practice, as I think it's a core design decision that has to be made right from the project start and these approaches should not be mixed up randomly without a specific reason. Maybe the answer is just a simple "There is no official recommendation which decision to make".

like image 322
fishbone Avatar asked Oct 16 '22 14:10

fishbone


1 Answers

In my opinion, you should use the new operator to create new objects of your class if you need to perform complex operations on the object itself.

If in case you just need to access the properties only, you may use the object literal to create a new object.

This has got advantages like encapsulation, inheritance, etc. which a developer coming from the Java background could better relate to.

If you directly assign an object like below, then you have to explicitly set functions in it, for example, getName function.

hero: Hero = {
  id: 1,
  name: 'Windstorm',
  getName: function(){ // returns name }
};

However, by defining a class Hero with a function getName and then creating an instance of that class, you would automatically get that function, no matter how many times you create instances.

For a better understanding of Object Oriented Javascript, you may follow the link below:-

https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS


Regarding the below issue,

"People (who don't understand TypeScript's type concept) complain about the HttpClient not converting the returned plain object to their model class type."

HttpClient simply returns an object which the server sends, it is on JS to convert it into the required form. You can always map the response into the required model instance by using its constructor which could be defined as below:-

constructor(hero){
  this.id = hero.id;
  this.name = hero.name;
}

and you may map the array returned from the server like below:-

map(hero => new Hero(hero))
like image 76
Ankit Sharma Avatar answered Oct 20 '22 01:10

Ankit Sharma