(TypeScript) 扩展 KnockoutObservableArray

(TypeScript) Extending KnockoutObservableArray

我想制作一个松散 MyKOArray<T> extends KnockoutObservableArray<T> 的 TypeScript class。这可能吗?如果是这样,有没有紧凑的方法来做到这一点?

===

编辑:为什么?

我正在尝试使用以下模式分离我的系统(仅记录 "interesting case"):

这在我的单个实例上运行良好。 state 方法被广泛询问(和更新)以确保有效的操作。

我想在我的 KOArrays 上复制图案。这样,我就可以区分尚未加载的空数组和恰好为空的已加载数组。我还可以向 KOArray 添加 stateerror_message 以反映我的实例的行为。

总之,你描述的方式是不可能的。

长话短说

Knockout 不是以面向对象的方式实现的。所以基本上它公开的几乎所有东西都是函数或普通对象等。原型处理用于 扩展 例如 ko.observable 返回的函数实例。所以基本上 从任何类型的 Knockout 中继承 在 OOP 意义上是不可能的。

如果您需要继承来添加功能,您可以将新方法添加到 ko.observableArray.fn 对象。然后此函数将在之后的所有 observableArray 个实例上调用。这里有一个简单的例子。

ko.observableArray.fn.hasElements = function() {
  return this().length > 0;
}
...
if (myModel.selectedItems.hasElements()) {
  ...
}

如果你需要继承来限制某些东西,你可以像这样添加自己的工厂函数。

ko.myRestrictedObservableArray = function(initialValue) {
  if (!initialValue || !initialValue.length) {
    throw new "You can create an observable array only with a non-empty initial value";
  }

  return ko.observableArray(initialValue);
}

如果您愿意,您甚至可以 覆盖 原始函数,例如像这样。虽然,在大多数情况下这不是一个好的做法。

var _original = ko.observableArray;
ko.observableArray = function(initialValue) {
  // ... do your custom things
  var array = _original.call(this, initialValue);
  // ... do your custom things 
  return array;
}

如果您还有其他要求,请在您的问题中更详细地描述。

根据@Zoltan 的反馈,我最终采用了以下方法。我确信存在错误和优化的机会,但它让我可以在 Typescript class 中编写所有内容(在两个方向上进行适当的类型检查):

在纯 JS 中(例如 HTML 文件或单独的 JS 文件中的 <script>):

function RestCollection(initialValue) {
    const fn = ko.observableArray(initialValue);
    // Static properties
    ko.utils.extend(fn.constructor, RestCollectionMixin);
    // Methods (already constructed so must attach directly, not to prototype)
    const methods = Object.getOwnPropertyNames(RestCollectionMixin.prototype);
    for (let i=0; i<methods.length; i++) {
        if (methods[i] == "constructor") continue;  // don't move over the constructor
        fn[methods[i]] = RestCollectionMixin.prototype[methods[i]].bind(fn)
    }
    // Constructed properties
    ko.utils.extend(fn, new RestCollectionMixin());
    return fn;
} {}

// RestCollectionMixin needs this; don't return or it will break the constructor
function KnockoutObservableArrayClass() {}

在 TS 文件中:

// abstract is not passed to JS so this prevents misuse without breaking the RestCollection constructor
abstract class RestCollectionMixin<T> extends KnockoutObservableArrayClass<T> { // extends handles parent method access
    static FSM = class {
        static STATE_INIT = 'initializing';
        static STATE_READY = 'ready';
        static STATE_SAVING = 'save_requested';
        static STATE_DELETING = 'delete_requested';
        static STATE_DELETED = 'deleted';
        static STATE_ERROR = 'error';
    };
    public states() { // convenience accessor
        return this.constructor.FSM
    }
    public state:KnockoutObservable<string> = ko.observable(this.states().STATE_INIT);

    public processRestError(results) {
        this.state(this.states().STATE_ERROR)
        ...
    }
    ...
}

最后,RestCollectionKnockoutObservableArrayClass 的定义文件使 TS 检查有效:

// provide KnockoutObservableArray properties and methods to the Mixin
interface KnockoutObservableArrayClass<T> extends KnockoutObservableArray<T> {
    new<T>(initialValue): KnockoutObservableArray<T>
}
declare const KnockoutObservableArrayClass:KnockoutObservableArrayClass<any>;

// Define the focal class, capturing all extensions in RestCollectionMixin
interface RestCollection<T> extends RestCollectionMixin<T> {
    new<T>(initialValue): RestCollection<T>
}
declare const RestCollection:RestCollection<any>;