简体   繁体   中英

Extend JavaScript object prototype by typescript class

tl;dr: I need to have the compiled Typescript prototype definitions applied to objects I have defined to be of that class.


Situation: I need to extend a JavaScript object by some business logic defined in a typescript class.
This might look somewhat like:

class Address
{
  constructor(
    public Street: string,
    public Number: number,
    public Zip: number,
    public City: string)
  { }

  public get FullAddress()
  {
    return this.Street + ' ' + this.Number + ', '
      + this.Zip + ' ' + this.City;
  }
}

The compiled JS adds the code to extend the object prototype by FullAddress . If I call new Address('Somestreet', 5, 3564, 'SomeCity') everything works like a charm.


The Problem: when I get some JS object (in my case using angular's $http )

$http.get('/api/address').then((answer: AngularPromise<Address[]>) => 
{
  console.log(answer.data[0].FullAddress());
});

I can call the function FullAddress on the object since in Typescript the function is defined on the class definition.

Now when I execute the code in the browser answer.data.FullAddress() is not defined (which makes sense since Typescript just provides the type definition and never touched the object.


Attempted Solution : One possible solution would be calling the constructor for each object (somewhat like following)

$http.get('/api/address').then((answer: AngularPromise<Address[]>) => 
{
  for(var i = 0; i < answer.data.length; i++)
  {
    answer.data[0] = new Address(answer.data[0].Street, ans.....);
  }
  console.log(answer.data[0].FullAddress());
});

and maybe overload the Address constructor to accept the complete object to reduce boilerplate.


The actual Question: Since the Object I need is a way more complex nested structure than that simple Address construct described here, above solution would require me to write an enormous amount of boilerplate and I feel like there has to be a better solution to that problem.

Had this same issue! One way to go, as you said is to make a constructor and feed all the info in - a bit tedious and seems wrong. We ended up making a MapTo function that can map a generic object to a strong class:

public static MapTo(jsonObject, nameSpace, classType) {
    var instance = new classType();
    for (var prop in jsonObject) {
        if (!jsonObject.hasOwnProperty(prop)) {
            continue;
        }

        if (jsonObject[prop] == null) {
            instance[prop] = null;
        } else if (typeof jsonObject[prop] === 'object') {
            if (nameSpace[prop]) {
                instance[prop] = this.MapTo(jsonObject[prop], nameSpace, nameSpace[prop]);
            } else {
                instance[prop] = jsonObject[prop];
            }
        } else {
            instance[prop] = jsonObject[prop];
        }
    }

    return instance;
}

And the usage would be:

var strongAddress = MapTo(answer.data[0], Models, Models.Address); //I assumed your class was in a namespace called "Models"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM