Typescript object VS javascript object

The use of Typescript is amazing for web/app development, however we must remember that Typescript is a javascript’s superset and it will be transpiled in pure js with all limitation of the case.

Let’s see a courios case I’ve faced today.

export class User
{
   // class attributes
   public name: string = "";
   public surname: string = "";
   // class properties
   public get FullName(): string
   {
     return this.name + " " + this.surname;
   }
   public SayHello()
   {
     console.log("Hello " + this.FullName);
   }
}

How you can see on the code block above, we have a class named User with two attributes, Name and Surname, and a readonly property, FullName.

function ConvertObject<T>(arg: any): T
{
    const result: T = {} as T;
    return Object.assign(result, arg) as T;
}

On the code above we had created a function that receive an object and “cast” it to T (TS is unable to CAST directly an any object, so we use object.assign to copy arg values into result).

import { User } from "./user";

const user: User = new User();
user.name = "Andrea";
user.surname = "Abbondanza";
console.log(user.FullName); // this will print "Andrea Abbondanza"

const obj = { name: "Vincenzo", surname: "Abbondanza" };
const user1 = ConvertObject<User>(obj);
console.log(user1.FullName); // <-- this will give you an error, FullName is undefined

How you can see, user1 is knew from TS compiler and intellisense as type User but it is essentially a simple json object with two fields, name and surname.

The methods and properties are not assigned by object.assign, also because this has the definition of: “The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object. “

Methods and properties are not enumerable, so thats it.

const user: User = new User();
const obj = { name: "Vincenzo", surname: "Abbondanza" };
for (const key in obj) 
{
    if (obj.hasOwnProperty(key)) 
    {
        user[key] = obj[key];        
    }
}

console.log(user.FullName); // <-- this will work

In the code above you can see that user is recognized as type User and it is of type user, so all properties and methods will works. Essentially with this way we can copy a javascript object into a Typescript object.

If usually we talk about class, we can user also an object approach.

export default class Parent
{
   public CastToThis<T>(arg: any): T
   {
      for (const key in obj) 
      {
         if (obj.hasOwnProperty(key)) 
         {
           this[key] = obj[key];        
         }
      }
      return this as unknow as T; // needed for cast
   }
}

And then for all our models.

import { Parent } from "./parent";

export class User extends Parent
{
   // class attributes
   public name: string = "";
   public surname: string = "";
   // class properties
   public get FullName(): string
   {
     return this.name + " " + this.surname;
   }
   public SayHello()
   {
     console.log("Hello " + this.FullName);
   }
}

In this way all our classes can “cast” js object to themself, for example.

const obj = { name: "Vincenzo", surname: "Abbondanza" };
const user = new User().CastToThis<User>(obj); 
console.log(user.FullName);
user.SayHello();

NOTE: The concept is simple, but the row

this[key] = obj[key]; // or user[key] = obj[key]

May be invalid for your tslint/tscompiler options, in that case you must to find a way to apply the concept following the rules you’ve set in your project.

NOTE 1: You may asking because we use the forin and not the Object.assign, thats because Object.assign return always a json object, even if your target is an instance of type T.