initialize example clases array javascript interface typescript typescript1.6

javascript - example - typescript abstract class



Implementación de interfaz anónima/en línea en TypeScript (1)

Bien, finalmente descubrí el problema en la pregunta 2: estaba usando la flecha gruesa => para declarar el método del objeto aquí:

doThatThing(<Doable>{ private message: ''ahoy-hoy!'', do: () => { // using fat arrow: global scope replaces new object''s scope alert(this.message); } });

... que "chupó" el alcance global en el método. El problema se soluciona utilizando la sintaxis más larga, así:

doThatThing(<Doable>{ private message: ''ahoy-hoy!'', do: function() { // using "regular" anonymous function syntax, "this" meaning is preserved alert(this.message); } });

Así que en resumen:

  1. sin respuesta;
  2. Había un error tipográfico en mi código, y debería haber estado usando "function ()" en lugar de "=>"; y,
  3. El tipo de afirmación del objeto con la interfaz elimina el error del compilador.

Acabo de comenzar con TypeScript y trato de entender por qué la siguiente definición de objeto en línea no se considera válida. Tengo una colección de objetos: su tipo es irrelevante (para mí), pero implementan la interfaz de modo que cuando los recorro, sé que los métodos de la interfaz estarán presentes en cada objeto de la colección.

Encontré un error de "compilador" cuando intenté crear un objeto con información privada requerida para implementar el método requerido:

interface Doable { do(); } function doThatThing (doableThing: Doable) { doableThing.do(); } doThatThing({ private message: ''ahoy-hoy!'', // compiler error here do: () => { alert(this.message); } });

El mensaje de error del compilador es "Argumento de tipo ''{ message: string, do: () => void; }'' no se puede asignar al tipo Doable. El literal del objeto debe especificar propiedades conocidas, y el ''mensaje'' no existe en el tipo Doable" . Tenga en cuenta que se da el mismo mensaje si defino el objeto fuera de la llamada de función, es decir,

var thing: Doable; thing = { private message: ''ahoy-hoy!'', // error here do: () => { alert(this.message); } }; doThatThing(thing);

El mismo error ocurre si agrego métodos "inesperados" también:

doThatThing({ do: () => { alert("ahoy hoy"); }, doSecretly: () => { // compiler error here now alert("hi there"); } });

Miré el JavaScript y descubrí que this dentro de la definición del objeto en línea estaba siendo objeto de alcance al objeto global:

var _this = this; // wait, no, why!? function doThatThing(doableThing) { doableThing.do(); } doThatThing({ message: ''ahoy-hoy!'', do: function () { alert(_this.message); // uses global } });

Intenté buscar información sobre implementaciones en línea de interfaces en TypeScript, pero no pude encontrar nada que hablara específicamente de este problema.

Puedo confirmar que el JS compilado "arreglado" funciona según lo previsto:

function doThatThing(doableThing) { doableThing.do(); } doThatThing({ message: ''ahoy-hoy!'', do: function () { alert(this.message); } });

... y eso tiene sentido para mí, porque (por lo que yo entiendo) esto está implícitamente llamando al constructor del Objeto, por lo que this debería incluirse en la nueva instancia del Objeto.

Parece que la única solución es declarar cada implementación como una clase que implementa la interfaz, pero eso se siente realmente regresivo ya que solo voy a tener una instancia de cada clase. Si el único contrato con la función llamada es implementar la interfaz, ¿por qué el objeto no puede contener miembros adicionales?

Lo siento, esto resultó más largo de lo que pretendía ... en resumen, pregunto:

  1. ¿Por qué esa implementación de interfaz en línea ("clase anónima", como se diría en Java ) se considera inválida en TypeScript? Específicamente, ¿qué significa ese error del compilador y contra qué protege?
  2. ¿Por qué es la reasignación de alcance al objeto global generado en el JavaScript "compilado"?
  3. Suponiendo que sea mi error (por ejemplo, que el error del compilador es necesario para protegerse contra alguna condición no deseada), ¿es la única solución realmente para declarar explícitamente una clase por adelantado, como así?

interface Doable { do() : void; } class DoableThingA implements Doable { // would prefer to avoid this ... private message: string = ''ahoy-hoy''; do() { alert(this.message); } } class DoableThingB implements Doable { // ... as well as this, since there will be only one instance of each do() { document.getElementById("example").innerHTML = ''whatever''; } } function doThatThing (doableThing: Doable) { doableThing.do(); } var things: Array<Doable>; things = new Array<Doable>(); things.push(new DoableThingA()); things.push(new DoableThingB()); for (var i = 0; i < things.length; i++) { doThatThing(things[i]); }

PD: El error del compilador solo apareció cuando actualicé a TS 1.6 hoy, aunque el error de alcance defectuoso en el JS compilado ocurre tanto en 1.6 como en 1.5.

Actualización: François Cardinaux proporcionó un enlace a esta respuesta , que recomienda el uso de una aserción de tipo, pero esto solo elimina el error del compilador y en realidad provoca un error lógico debido a un alcance inadecuado :

interface Doable { do(); } function doThatThing (doableThing: Doable) { doableThing.do(); } doThatThing(<Doable>{ // assert that this object is a Doable private message: ''ahoy-hoy!'', // no more compiler error here do: () => { alert(this.message); } });

Mirando el JS compilado, esto es incorrecto:

var _this = this; // very wrong, and now hidden function doThatThing(doableThing) { doableThing.do(); } doThatThing({ message: ''ahoy-hoy!'', do: function () { alert(_this.message); // s/b "this.message", which works in JS (try it) } });