2

Say I have the following class:

export class MyClass { str: string = ''; foo() { console.log(this.str); } } 

Then, in some other code:

var myObj = { str: 'Hello World'; } 

How can I convert myObj into a MyClass instance, so the following line works:

myObj.foo(); // writes 'Hello World' to the console 

(Please note that I cannot change the creation of myObj, because it's created in another library)

***** EDIT: *****

I'm still looking for a solution for this. The main problem is that MyClass has references to other classes, which maybe have references to MyClass. It's a whole object graph that I'm trying to convert to TypeScript classes.

Of every class and every property I know its type, and it matches perfectly with the classes and properties defined on MyClass.

0

    5 Answers 5

    1

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

    function becomeMyClass(o){ var fn1=function(){ var thing; MyClass.apply(arguments); //note: shallow copy only for(thing in o){ if(Object.prototype.hasOwnProperty .call(o,thing)){ this[thing]=o[thing]; } } }; fn1.prototype=Object.create(MyClass.prototype); return new fn1([].slice.call(arguments,1)); } function MyClass(){ 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 myObj console.log(myC instanceof MyClass);//true 
      1

      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.

      1
      • But in this case the MyClass constructor won't be executed, will it? So there's the same problem as in using __proto__.CommentedFeb 2, 2014 at 17:52
      1

      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 = new MyClass(); 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 = new MyClass(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:

      3
      • I'm looking for a generic way that doesn't create a new object. I have many references to the objects I want to convert, and they are much more complex than just with one property str.CommentedJan 30, 2014 at 15:31
      • Do the property names always match?
        – Fenton
        CommentedJan 30, 2014 at 16:26
      • Yes, the property names do always match.CommentedOct 23, 2014 at 9:44
      0

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

      export class Util { static become(obj: any, newClass: any) { obj.__proto__ = (<any>(new newClass())).__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__.

      2
      • 1
        If there happened to be code in the constructor for the other class, it won't have fired, making this solution not necessarily portable in all cases. You might want to consider just copying the data into a new instance. That way constructors and property setters have a chance to execute.CommentedJan 30, 2014 at 13:40
      • 1
        You should not fiddle with __proto__. It is non-standard in ES5 and below, and even in ES6 it is discouraged to set it yourself.
        – Arnavion
        CommentedFeb 1, 2014 at 9:01
      0

      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).

        Start asking to get answers

        Find the answer to your question by asking.

        Ask question

        Explore related questions

        See similar questions with these tags.