1

I am trying to figure out if a Typescript object is same as a Javascript object. I have a typescript variable into which I want to typecast result of JSON.parse which I suppose creates a javascript object from a json but I am unable to do it.

I have the following two classes

export class User {
  constructor (public firstname:string,
               public lastname:string,
               public email:string,
               public password:string=""){} 
}

export class UserProfileAPI {
  'external-profile': User;
  constructor(externalProfile:User){ 
    this['external-profile'] = externalProfile;
  }
}

I have created a spec to test that an object created explicitly is same or similar to object created by json.parse but they don't seem to be.

 fit('should test if Typescript object is same as Javascript object',()=>{
    let user = new User('manu','chadha','test@test.com');
    let dummyUserProfile:UserProfileAPI= new UserProfileAPI(user);
    console.log('dummy profile is ',dummyUserProfile);
    let dummyProfile2:UserProfileAPI = JSON.parse('{"external-profile":{"firstname":"manu","lastname":"chadha","email":"test@test.com"}}');
    console.log('dummy profile 2 is ',dummyProfile2);
    console.log('dummy profile1 == dummy profile 2',(dummyUserProfile == dummyProfile2));
    console.log('dummy profile1 === dummy profile 2',(dummyUserProfile == dummyProfile2));
    expect(dummyUserProfile).toEqual(dummyProfile2);
    expect(dummyUserProfile).toBe(dummyProfile2);
  });

In the above case, dummyUserProfile is printed as LOG: 'dummy profile is ', UserProfileAPI{external-profile: User{firstname: 'manu', lastname: 'chadha', email: 'test@test.com', password: ''}} but dummyProfile2 is printed as LOG: 'dummy profile 2 is ', Object{external-profile: Object{firstname: 'manu', lastname: 'chadha', email: 'test@test.com'}} and both the comparisons return false. Why?

Manu Chadha
  • 15,555
  • 19
  • 91
  • 184
  • There may be more to this question, but likely the most important takeaway: Comparing two objects will [**never return `true`**](https://jsfiddle.net/ts02dgr1/) unless you compare an object to itself. – Tyler Roper Jan 04 '19 at 19:11
  • Then how should I test that the object returned from json.parse is of a certain type? – Manu Chadha Jan 04 '19 at 19:13
  • As far as I can tell, you are not comparing *types* anywhere in your code, but rather just comparing the two objects themselves. I'm not all that well-versed in TS so I'll let someone else chime in with more detail. – Tyler Roper Jan 04 '19 at 19:14
  • This has nothing to do with JS vs TS. `{} === {}` will always give you false, for the same reason you're getting false. Object equality uses reference equality, not value equality. –  Jan 04 '19 at 19:40

1 Answers1

2

First of all, as several others have already said in comments: in JS objects never == or === unless they are the same reference. Equality by value doesn't work, ie {} == {} is always false. But given an object like const obj = {} then obj == obj is true. This has nothing to do with TypeScript.

Now to this part of your question:

I am trying to figure out if a Typescript object is same as a Javascript object. I have a typescript variable into which I want to typecast result of JSON.parse which I suppose creates a javascript object from a json but I am unable to do it.

Two important things here you should understand:

  • What you are calling a "TypeScript object" and a "JavaScript object" is really a JavaScript object constructor (or instance of) and a plain JavaScript object. Again this has nothing specifically to do with TypeScript. In ES6 you can define class object types and even in ES5 you can with an old-school constructor function.

  • What you call a "typecast" in TypeScript is really just a type assignment (or you may have tried a type "assertion"), meaning it does not change the object in any way, it just informs the compiler what you assume the type of the object should be. You can assign any to any type, but it doesn't mean it's true. There's actually a lot of ways you can break your code by writing wrong type assignments and assertions.

So your real issue is that JSON.parse() gives you a plain JS object and you want to turn it into a JS object type instance. There's no built-in way to do this in JS unfortunately but of course you can manually do it after decoding the JSON. See: Parse JSON String into a Particular Object Prototype in JavaScript

A simple example in your case might look like this:

function decodeUserFromJSON(userJSON: string): User {
   const userObj = JSON.parse(userJSON);
   const { firstname, lastname, email, password } = userObj;
   const user = new User(firstname, lastname, email, password);
   return user;
}

Depending on how your test framework compares object instances you should be able to check for equality something like this:

const user = new User("a", "b", "foo@bar.com", "1");
const decodedUser = decodeUserFromJSON(`{"firstname": "a", "lastname": "b", "email": "foo@bar.com", "password": "1" }`);
expect(decodedUser).toEqual(user);
Aaron Beall
  • 49,769
  • 26
  • 85
  • 103