Search code examples
jsontypescripthasownproperty

Weird .hasOwnProperty behaviour


In an effort to properly instantiate Typescript objects from data received over HTTP as JSON, I was exploring the possibility of using the for..in loop coupled with .hasOwnProperty() like so:

class User {
    private name: string;
    private age: number;

    constructor(data: JSON) {
        console.log('on constructor\ndata', data);

        for (var key in data) {
            console.log('key:', key);
            if (User.hasOwnProperty(key)) {
                console.log('User has key:', key);
                this[key] = data[key];
            }
        }
    }

    displayInfo(): string{
        return JSON.stringify(this);
    }
}

let button = document.createElement('button');
button.textContent = "Test";
button.onclick = () => {
    try{
        let json = JSON.parse('{"name": "Zorro","age": "24"}');
        let usr = new User(json);
        console.log(usr.displayInfo());
    }catch (error){
        alert(error);
    }

}

document.body.appendChild(button);

Using similar code in my project fails completely. That is expected as the compiled JS code has no awareness of the private TS vars and so, hasOwnProperty is always false.

However, I was using the Typescript Playground, and running that code there produces the following output in the console:

on constructor
data Object {name: "Zorro", age: "24"}
key: name
User has key: name
key: age
{"name":"Zorro"}

As you can see, there are clearly some unexpected things happening here. The first key is recognized and the new User instance is initialized with the value from the JSON, yet that does not happen for the second key.

Can someone explain why this happens?


Solution

  • As was pointed out in the comments, you should be using this.hasOwnProperty instead of User.hasOwnProperty. And as you noticed, this code is busted anyway because the property declarations in the class don't actually create own properties on the object (they would need to be initialized for this to happen).

    But why did you get a hit on the name key? The User object is a constructor function for your class. Functions do have a name property:

    function fn() { }
    console.log(fn.name); // prints 'fn'
    

    They don't have an age property, of course.