Búsqueda de sitios web

angular - ¿Leer nombres de propiedades de una clase en TypeScript?


Teniendo una clase (por ejemplo, WikipediaSearchResult) con algunas propiedades en TypeScript, ¿es posible acceder a ellas? Tal vez esta pregunta sea un poco ingenua, pero me pregunto si podría escribir el siguiente código sin nombres de propiedades duplicados:

function mergeTo(from:any, to:any={}, properties:Array<string>=[]) {
  if (!!from) {
    for (var property of properties) {
      // no deep copy here ;-)
      to[property] = from[property];
    }
  }
}

class WikipediaSearchResult /* implements IWikipediaSearchResult */ {

  lang:string;
  summary:string;
  title:string;
  wikipediaUrl:string;

  constructor(obj?:any) {

    mergeTo(obj, this, [
      // --> How to avoid this list? <--
      'lang', 'summary', 'title', 'wikipediaUrl'
    ]);

  }

}

var result = new WikipediaSearchResult({
  title: 'Zürich', 
  wikipediaUrl: 'https://en.wikipedia.org/wiki/Z%C3%BCrich'
});

console.log(result);

Por supuesto, existen algunas bibliotecas de terceros como Underscore.js, pero difiere de, por ejemplo, _.clone(...) ya que solo quiero clonar propiedades específicas e ignorar todas las demás propiedades que puedan ser proporcionadas por obj o from respectivamente.

Otra forma podría ser usando por ejemplo _.create(WikipediaSearchResult.prototype, { title: 'Zürich' }), aún no lo he probado pero usará la propiedad prototype de JavaScript. Sería genial usar el mecanismo interno de TypeScript.

Una idea que se me ocurrió es crear una instancia "falsa" y leer su clave. Me pregunto si alguien tiene una mejor variante.

Respuesta #1

Inicializar las propiedades de la clase WikipediaSearchResult permite usar this como una "plantilla":

function mergeTo(from:any, to:any={}, properties:Array<string>=[]) {
  // same as in question
}

function mergeTo2(from:Object, to:Object):Object {
  // _.keys from underscore
  return mergeTo(from, to, _.keys(to));
}

class WikipediaSearchResult {

  lang:string = undefined;
  summary:string = undefined;
  title:string = undefined;
  wikipediaUrl:string = undefined;

  constructor(obj?:any) {
     util.mergeTo2(obj, this);
  }

}

var result = new WikipediaSearchResult({
  title: 'Zürich', 
  wikipediaUrl: 'https://en.wikipedia.org/wiki/Z%C3%BCrich'
});

console.log(result);

Todavía buscando otras variantes...

Respuesta #2

Puedes aplicar a cada una de las propiedades copiables un decorador personalizado:

  @Copiable
  lang:string;

Luego, dentro de la función decoradora @copiable almacenarás el nombre de la propiedad objetivo en alguna colección estática.

function Copiable(target: any, key: string) 
{
    CopiableProperties.push(key); 
}

Luego, en el método mergeTo, podrás iterar sobre todos los nombres de propiedades copiables almacenados en CopiableProperties.

Podría ser un poco exagerado, pero te permitirá evitar duplicados. Espero que esto ayude.