Mixins a máquina de escribir

votos
6

Estoy jugando con mecanografiado, y tengo un par de mixins funcionales , Eventabley Settableque me gustaría mixin a una Modelclase (pretender que es algo así como un modelo Backbone.js):

function asSettable() {
  this.get = function(key: string) {
    return this[key];
  };
  this.set = function(key: string, value) {
    this[key] = value;
    return this;
  };
}

function asEventable() {
  this.on = function(name: string, callback) {
    this._events = this._events || {};
    this._events[name] = callback;
  };
  this.trigger = function(name: string) {
    this._events[name].call(this);
  }
}

class Model {
  constructor (properties = {}) {
  };
}

asSettable.call(Model.prototype);
asEventable.call(Model.prototype);

El código anterior funciona bien, pero no se compilará si trataba de utilizar uno de los métodos mixtos adicionales como pueden (new Model()).set('foo', 'bar').

Puedo solucionar este problema

  1. la adición de interfacedeclaraciones para los mixins
  2. declarando ficticias get/ set/ on/ triggermétodos en la Modeldeclaración

¿Hay una manera limpia en torno a las declaraciones ficticias?

Publicado el 04/10/2012 a las 04:20
fuente por usuario
En otros idiomas...                            


3 respuestas

votos
12

He aquí una manera de acercarse a mixins utilizando interfacesy un static create()método. Interfaces de la herencia múltiple de modo que le impide tener que redefinir el interfacesde sus mixins y el static create()método se ocupa de dar vuelta una instancia de Model()como una IModel(la <any>que se necesita fundido para suprimir una advertencia del compilador.) Tendrá que duplicar todos las definiciones de los usuarios para Modelel IModelque aspira pero parece que la manera más limpia para conseguir lo que quiere en la versión actual del texto mecanografiado.

Edit: He identificado un enfoque ligeramente más fácil de mixins de apoyo e incluso han creado una clase de ayuda para definirlos. Los detalles se pueden encontrar aquí .

function asSettable() {
  this.get = function(key: string) {
    return this[key];
  };
  this.set = function(key: string, value) {
    this[key] = value;
    return this;
  };
}

function asEventable() {
  this.on = function(name: string, callback) {
    this._events = this._events || {};
    this._events[name] = callback;
  };
  this.trigger = function(name: string) {
    this._events[name].call(this);
  }
}

class Model {
  constructor (properties = {}) {
  };

  static create(): IModel {
      return <any>new Model();
  }
}

asSettable.call(Model.prototype);
asEventable.call(Model.prototype);

interface ISettable {
    get(key: string);
    set(key: string, value);
}

interface IEvents {
    on(name: string, callback);
    trigger(name: string);
}

interface IModel extends ISettable, IEvents {
}


var x = Model.create();
x.set('foo', 'bar');
Respondida el 04/10/2012 a las 06:46
fuente por usuario

votos
3

La forma más limpia de hacerlo, aunque incluya todavía requiere declaraciones de tipo doble, es definir el mixin como un módulo:

module Mixin {
    export function on(test) {
        alert(test);
    }
};

class TestMixin implements Mixin {
    on: (test) => void;
};


var mixed = _.extend(new TestMixin(), Mixin); // Or manually copy properties
mixed.on("hi");

Una alternativa al uso de interfaces es entrar ilegalmente en él con las clases (A pesar de que a causa de herencia múltiple, tendrá que crear una interfaz común para los mixins):

var _:any;
var __mixes_in = _.extend; // Lookup underscore.js' extend-metod. Simply copies properties from a to b

class asSettable {
    getx(key:string) { // renamed because of token-clash in asEventAndSettable
        return this[key];
    }
    setx(key:string, value) {
        this[key] = value;
        return this;
    }
}

class asEventable {
    _events: any;
    on(name:string, callback) {
        this._events = this._events || {};
        this._events[name] = callback;
    }
    trigger(name:string) {
        this._events[name].call(this);
  }
}

class asEventAndSettable {
   // Substitute these for real type definitions
   on:any;
   trigger:any;
   getx: any;
   setx: any;
}

class Model extends asEventAndSettable {
    /// ...
}

var m = __mixes_in(new Model(), asEventable, asSettable);

// m now has all methods mixed in.

Como les comentaba sobre la respuesta de Steven, mixins realmente debería ser una característica mecanografiado.

Respondida el 04/10/2012 a las 07:04
fuente por usuario

votos
1

Una solución es no utilizar el sistema de clases mecanografiado, pero sólo el Systeme de tipos e interfaces, además de la palabra clave 'nuevo'.

    //the function that create class
function Class(construct : Function, proto : Object, ...mixins : Function[]) : Function {
        //...
        return function(){};
}

module Test { 

     //the type of A
    export interface IA {
        a(str1 : string) : void;
    }

    //the class A 
    //<new () => IA>  === cast to an anonyme function constructor that create an object of type IA, 
    // the signature of the constructor is placed here, but refactoring should not work
    //Class(<IA> { === cast an anonyme object with the signature of IA (for refactoring, but the rename IDE method not work )
    export var A = <new () => IA> Class(

        //the constructor with the same signature that the cast just above
        function() { } ,

        <IA> {
            //!! the IDE does not check that the object implement all members of the interface, but create an error if an membre is not in the interface
            a : function(str : string){}
        }
    );


    //the type of B
    export interface IB {
        b() : void;
    }
    //the implementation of IB
    export class B implements IB { 
        b() { }
    }

    //the type of C
    export interface IC extends IA, IB{
        c() : void;
        mystring: string;
    }

     //the implementation of IC
    export var C = <new (mystring : string) => IC> Class(

        //public key word not work
        function(mystring : string) { 

            //problem with 'this', doesn't reference an object of type IC, why??
            //but google compiler replace self by this !!
            var self = (<IC> this);
            self.mystring = mystring;
        } ,

        <IC> {

            c : function (){},

            //override a , and call the inherited method
            a: function (str: string) {

                (<IA> A.prototype).a.call(null, 5);//problem with call and apply, signature of call and apply are static, but should be dynamic

                //so, the 'Class' function must create an method for that
                (<IA> this.$super(A)).a('');
            }

        },
        //mixins
        A, B
    );

}

var c = new Test.C('');
c.a('');
c.b();
c.c();
c.d();//ok error !
Respondida el 23/01/2013 a las 00:34
fuente por usuario

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more