Примеси в машинописном

голоса
6

Я играл с машинописью, и у меня есть пара функциональных Примеси , Eventableи Settable, что я хотел бы подмешать к Modelклассу (вид , что это что - то вроде модели 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);

Код выше работает отлично, но не компилируется , если я пытался использовать один из смешанных в методах , как (new Model()).set('foo', 'bar').

Я могу работать вокруг этого

  1. добавление interfaceдеклараций для Mixins
  2. объявить фиктивные get/ set/ on/ triggerметоды в Modelдекларации

Есть ли чистый путь вокруг заявлений фиктивных?

Задан 04/10/2012 в 04:20
источник пользователем
На других языках...                            


3 ответов

голоса
12

Вот один из способов приблизиться к Примеси , используя interfacesи static create()метод. Интерфейсы поддерживает множественное наследование , так что предотвращает Вас от необходимости переопределить interfacesдля Mixins и static create()метод заботится о давая Вам экземпляр в Model()качестве IModel( <any>бросок необходим для подавления предупреждения компилятора.) Вы должны будете дублировать все ваши определения членов для Modelна IModelкоторый сосет , но это , кажется , как самый чистый способ добиться того, что вы хотите в текущей версии машинописи.

Изменить: Я определил несколько более простой подход к поддержке Mixins и даже создал вспомогательный класс для определения их. Подробную информацию можно найти здесь .

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');
Ответил 04/10/2012 в 06:46
источник пользователем

голоса
3

Чистейший способ сделать это, Althought она по-прежнему требует декларации двойных типа, чтобы определить подмешать в качестве модуля:

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

Альтернатива с использованием интерфейсов, чтобы взломать его с классами (хотя из-за множественное наследование, вам необходимо создать общий интерфейс для 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.

Как я прокомментировал ответ Стивена, Mixins действительно должны быть функцией машинописи.

Ответил 04/10/2012 в 07:04
источник пользователем

голоса
1

Одним из решений являются не использовать систему класса машинописи, но только Systeme типов и интерфейсов, в дополнении к ключевому слову «новым».

    //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 !
Ответил 23/01/2013 в 00:34
источник пользователем

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