我在玩TypeScript,我有几个功能混合器,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')这样的混合方法之一,就不会编译。
我可以通过
interface声明get/set/on/trigger声明中声明虚拟Model方法有一个干净的方法绕过虚拟声明吗?
发布于 2020-05-22 09:56:24
几年前,有一种新的方法被构建到类型记录中,称为“混合类”。文档中没有很好地描述它,但是它们确实有一个广受好评的例子来很好地描述模式。适用于您的情况,它可能如下所示:
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'),并提供完整的键入支持。没有虚假的声明。
发布于 2012-10-04 05:46:17
这里有一种使用interfaces和static create()方法来处理混合器的方法。接口支持多重继承,这样您就不必为混合器重新定义interfaces,而static create()方法则负责将Model()的实例作为IModel (需要<any>强制转换来抑制编译器警告)。您需要在Model上复制IModel的所有成员定义,这很糟糕,但这似乎是在当前版本的TypeScript中实现所需的最干净的方法。
编辑:我已经确定了一种稍微简单一些的方法来支持混合器,甚至创建了一个用于定义它们的助手类。详细信息可以找到到这里来.
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');发布于 2012-10-04 06:04:51
尽管它仍然需要双类型声明,但最干净的方法是将混和定义为一个模块:
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");使用接口的另一种方法是使用类对其进行黑客攻击(尽管由于多重继承,您需要为混联器创建一个公共接口):
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特性。
https://stackoverflow.com/questions/12719844
复制相似问题