Reputation: 14445
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)
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
.
Upvotes: 2
Views: 2680
Reputation: 250972
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();
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:
Upvotes: 1
Reputation: 3968
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).
Upvotes: 0
Reputation: 33701
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.
Upvotes: 1
Reputation: 39280
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
Upvotes: 1
Reputation: 14445
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__
.
Upvotes: 0