Mixins dactylographiée

voix
6

Je joue autour avec tapuscrit, et j'ai quelques mixins fonctionnels , Eventableet Settableque je voudrais mixin à une Modelclasse (faire semblant qu'il est quelque chose comme un modèle 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);

Le code ci - dessus fonctionne très bien, mais ne compilerait pas si j'essayé d'utiliser l' une des méthodes mixtes dans comme (new Model()).set('foo', 'bar').

Je peux contourner ce problème en

  1. l' ajout de interfacedéclarations pour les mixins
  2. déclarant factices get/ set/ on/ triggerméthodes dans la Modeldéclaration

Est-il possible de nettoyer les déclarations fictives?

Créé 04/10/2012 à 04:20
source utilisateur
Dans d'autres langues...                            


3 réponses

voix
12

Voici une façon d'aborder mixins à l' aide interfaceset une static create()méthode. Interfaces prennent en charge l' héritage multiple de sorte que vous évite d'avoir à redéfinir le interfacespour vos mixins et la static create()méthode prend soin de vous redonner une instance de Model()comme IModel(le <any>casting est nécessaire pour supress un avertissement du compilateur.) Vous devrez dupliquer tous vos définitions membres pour Modelle IModelqui aspire , mais il semble que la manière la plus propre pour obtenir ce que vous voulez dans la version actuelle dactylographiées.

edit: je l' ai identifié une approche légèrement plus simple à mixins de soutien et ont même créé une classe d'aide pour les définir. Les détails peuvent être trouvés ici .

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');
Créé 04/10/2012 à 06:46
source utilisateur

voix
3

La propre façon de le faire, il faut encore althought déclarations de type double, est de définir le mixin en tant que module:

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");

Une alternative à l'utilisation des interfaces est de pirater avec des classes (Bien que à cause de l'héritage multiple, vous devez créer une interface commune pour les 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.

Comme je l'ai commenté la réponse de Steven, mixins devrait vraiment être une caractéristique dactylographiée.

Créé 04/10/2012 à 07:04
source utilisateur

voix
1

Une solution est de ne pas utiliser le système de classe dactylographiée, mais juste le type et de systeme interfaces, en plus du mot-clé « nouveau ».

    //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 !
Créé 23/01/2013 à 00:34
source utilisateur

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