首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >TypeScript中的Mixins

TypeScript中的Mixins
EN

Stack Overflow用户
提问于 2012-10-04 03:20:41
回答 4查看 9.9K关注 0票数 7

我在玩TypeScript,我有几个功能混合器EventableSettable,我想把它们混入到Model类中(假装它有点像Backbone.js模型):

代码语言:javascript
复制
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声明
  2. get/set/on/trigger声明中声明虚拟Model方法

有一个干净的方法绕过虚拟声明吗?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2020-05-22 09:56:24

几年前,有一种新的方法被构建到类型记录中,称为“混合类”。文档中没有很好地描述它,但是它们确实有一个广受好评的例子来很好地描述模式。适用于您的情况,它可能如下所示:

代码语言:javascript
复制
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();
  }
}

这样您就可以输入所需的内容,例如,您可以调用(new Model()).set('boo', 'bar'),并提供完整的键入支持。没有虚假的声明。

票数 2
EN

Stack Overflow用户

发布于 2012-10-04 05:46:17

这里有一种使用interfacesstatic create()方法来处理混合器的方法。接口支持多重继承,这样您就不必为混合器重新定义interfaces,而static create()方法则负责将Model()的实例作为IModel (需要<any>强制转换来抑制编译器警告)。您需要在Model上复制IModel的所有成员定义,这很糟糕,但这似乎是在当前版本的TypeScript中实现所需的最干净的方法。

编辑:我已经确定了一种稍微简单一些的方法来支持混合器,甚至创建了一个用于定义它们的助手类。详细信息可以找到到这里来.

代码语言:javascript
复制
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');
票数 12
EN

Stack Overflow用户

发布于 2012-10-04 06:04:51

尽管它仍然需要双类型声明,但最干净的方法是将混和定义为一个模块:

代码语言:javascript
复制
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");

使用接口的另一种方法是使用类对其进行黑客攻击(尽管由于多重继承,您需要为混联器创建一个公共接口):

代码语言:javascript
复制
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.

正如我对史蒂文的回答所评论的那样,混合器确实应该是一个TypeScript特性。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12719844

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档