Skip to content Skip to sidebar Skip to footer

How To Make A Js Object *become* A Typescript Class Instance

Say I have the following class: export class MyClass { str: string = ''; foo() { console.log(this.str); } } Then, in some other code: var myObj = { str: '

Solution 1:

Maybe something like this:(I've added the MyClass as JS code).

functionbecomeMyClass(o){
  var fn1=function(){
    var thing;
    MyClass.apply(arguments);
    //note: shallow copy onlyfor(thing in o){
      if(Object.prototype.hasOwnProperty
        .call(o,thing)){
          this[thing]=o[thing];
      }
    }
  };
  fn1.prototype=Object.create(MyClass.prototype);
  returnnewfn1([].slice.call(arguments,1));
}
functionMyClass(){
  this.str = "from myclass";
}
MyClass.prototype.foo=function(){
  console.log(this.str);
};
var myObj = {
  str:"from myObj"
}

myC = becomeMyClass(myObj);
console.log(myC.foo());//from myObjconsole.log(myC instanceofMyClass);//true

Solution 2:

Is this other library that creates the object always going to return that object from the function? You could create a .d.ts definitions file that defines that the specific function returns MyClass.

Solution 3:

I think the simplest solution, the most readable solution and the one with the fewest lines of code would be to just map it:

var myClass = newMyClass();
myClass.str = myObj.str;

myClass.foo(); 

If the str property is mandatory, you could make it a constructor parameter and reduce this by one line...

var myClass = newMyClass(myObj.str);

myClass.foo();

Update

If you have many classes in your program with the same properties, perhaps you could encapsulate those properties within a class. For example, if all the classes had properties name, nickname, avatar you might wrap them into a Profile class. This gives you one property to map should you need to take the profile from one class and add it to another.

However, you know your use case best, so you might be interested in this JavaScript port of auto-mapper, which should easily map your stuff if the properties all have the same names:

Solution 4:

Found it out, now I'm using the following utility method:

exportclassUtil {
    staticbecome(obj: any, newClass: any) {
        obj.__proto__ = (<any>(newnewClass())).__proto__;
    }
}

The following call converts myObj into a MyClass instance by assigning the right prototype:

Util.become(myObj, MyClass);

Maybe there's another, more elegant way that doesn't involve the use of __proto__.

Solution 5:

Since you say you have a lot of objects with an unknown list of properties, I take it you can't write a constructor for MyClass to take in an arbitrary object and create a MyClass instance from its properties. Therefore you can't meaningfully "convert" myObj to an instance of MyClass.

Fiddling with myObj's prototype is not a very nice thing to do. See the warning at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto

That leaves you with using duck typing: MyClass.foo.call(myObj); This will only work if MyClass's methods only refer to properties available on myObj, i.e., you don't expect the constructor of MyClass to have set any other properties to default values, etc. (since in this case the MyClass constructor has effectively never run).

Post a Comment for "How To Make A Js Object *become* A Typescript Class Instance"