7
votes

Mélangements dans Typescript

Je joue avec dossier, et j'ai un couple Mélangements fonctionnels , EVENABLE code> et réglable code>, que je voudrais mélanger à une classe modèle code> (prétendre que c'est quelque chose Comme un manuel 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);


1 commentaires

Peut-être une solution pour résoudre ceci à Microsoft / Typescript # 2919


4 Réponses :


12
votes

Voici une seule façon d'approcher des mixines à l'aide d'interfaces et à un statique Create () méthode. Les interfaces prennent en charge plusieurs héritage afin de vous empêcher de redéfinir les interfaces pour vos mixines et la méthode Static Create () Prévenez de vous donner une instance de Modèle () sous forme d'imodel (le est nécessaire pour supprimer un avertissement de compilateur.) Vous devrez dupliquer toutes vos définitions de votre membre. Pour modèle sur imodel qui craint, mais il semble que le moyen le plus propre d'atteindre ce que vous voulez dans la version actuelle de Typescript.

Edit: J'ai identifié une approche légèrement plus simple pour supporter des mixines et j'ai même créé une classe d'assistance pour les définir. Les détails peuvent être trouvés ici . xxx


2 commentaires

Était sur le point de poster ceci. TypeScript devrait vraiment être étendu à des mélanges de classes de support, car beaucoup de bibliothèques JS utilisent actuellement cela (par exemple, Backbone.js).


Depuis TS1.4, vous pouvez utiliser "Isettadible & Itevents" à la place "Imodel"



3
votes

Le moyen le plus propre de le faire, il faut toujours nécessiter toujours des déclarations de type double, consiste à définir le mixin sous forme de module: xxx

une alternative à l'utilisation d'interfaces est de pirater des classes ( Bien qu'en raison de multiples héritage, vous devrez créer une interface commune pour les mixines): xxx

comme je l'a commenté sur la réponse de Steven, les mélanges devraient vraiment être un dossier fonctionnalité.


3 commentaires

Je dirais même que la première version devrait simplement être la façon dont les dossiers implémentent des mixines - ne seraient pas trop difficiles.


Le problème avec ces deux options, si je comprends une sémantique TS correctement, est-ce qu'ils perdent la partie "fonctionnelle" des "mixines fonctionnelles". vous n'étendant que la classe avec les propriétés et la chose qui rend ce style de mixines bien est le fait que vous pouvez exécuter du code avec le mixin, ce qui vous donne la chance de sauver de petites pierres d'état, ou tout ce que vous avez besoin faire. Ce type d'utilisation des fonctions est l'OMI Qu'est-ce qui rend JS vaut quelque chose du tout (bien ... que et toute la chose de normes Web ...) par rapport à d'autres langues, mais sinon JS n'est qu'un faible remplacement.


Je crois que vous pouvez utiliser var mixte = _.Extend (testmixin.pototype, mixin); Pour rendre la vie plus facile



1
votes

Une solution consiste à n'utiliser pas le système de classe dossier, mais juste le système des types et des interfaces, en plus du mot clé 'nouveau'. xxx


0 commentaires

2
votes

Il y a une nouvelle façon qui a été construite dans Thypscript il y a quelques années, appelé "Cours de mixin". Il n'est pas bien couvert dans les documents, mais ils ont Un puits -Comment exemple pour décrire bien le motif. Appliqué à votre situation, il pourrait ressembler à quelque chose comme:

type Constructor = new (...args: any[]) => {}

function Settable<TBase extends Constructor>(Base: TBase) {
  return class extends Base {
    _props: Record<string, any> = {};

    get(key: string) {
      return this._props[key];
    }

    set(key: string, value: any) {
      this._props[key] = value;
      return this;
    }
  }
}

function Eventable<TBase extends Constructor>(Base: TBase) {
  return class extends Base {
    _events: Record<string, () => void> = {};

    on(name: string, callback: () => void) {
      this._events[name] = callback;
    }

    trigger(name: string) {
      this._events[name].call(this);
    }
  }
}

class Model extends Settable(Eventable(Object)) {
  constructor(properties = {}) {
    super();
  }
}


0 commentaires