首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何使用Typescript从knockout类继承?

如何使用Typescript从knockout类继承?
EN

Stack Overflow用户
提问于 2014-12-01 22:44:57
回答 4查看 1.8K关注 0票数 4

我正在使用knockout 3.x和Typescript,我想创建一个从KnockoutObservableArray<T>继承的强类型集合类,这样我的类型就可以是一个可观察的数组,但也有它自己的方法。所以我试了一下:

代码语言:javascript
运行
复制
export class Emails implements KnockoutObservableArray<Email>
{
    //add a new email to the list
    addItem() : void
    {
        var email = new ContactEmail();
        ...
        this.push(email);
    };
}

但这会给出以下错误:

代码语言:javascript
运行
复制
Class Emails declares interface KnockoutObservableArray<Email> but does not implement it:
Type 'Emails' is missing property 'extend' from type 'KnockoutObservableArray<Email>'.

如果我尝试添加extend方法,则需要实现peek方法,依此类推,这意味着我需要实现所有的KnockoutObservableArray。但是我不想重新实现它,我想扩展它,因为KnockoutObservableArray是一个接口而不是一个类,所以我看不到任何方法来实现它。有什么办法吗?

EN

回答 4

Stack Overflow用户

发布于 2014-12-03 22:59:41

在不太遥远的过去,这也是我曾经困扰过的事情。

为什么?

非常简单,有两个原因。

第一个原因是我没有从对象的角度真正理解JavaScript。对我来说,它一直是一种“脚本语言”,就是这样,我曾听到人们告诉我不是这样,但我(仍然)是一个C#爱好者,所以我很大程度上忽略了人们所说的,因为它看起来不像C#对象。

当我开始使用Type Script时,一切都改变了,TS以其JS输出的形式向我展示了对象JS的样子。

第二个原因是JS的灵活性,更重要的是knockout。

我喜欢这个想法,只需在C#代码中简单地更改我的JSON端点,并且除了对我的HTML进行一些调整之外,不需要在前端做任何更改。

如果我想要向输出对象添加一个新字段,那么我可以这样做,然后只需向表中添加一个新列,绑定正确的字段名称和完成的工作。

太棒了。

确实是这样,直到我开始被要求提供基于行的功能。它从简单的请求开始,比如能够删除行和执行内联编辑等操作。

这导致了许多奇怪的冒险,像这样:

Knockout JS + Bootstrap + Icons + html binding

还有这个:

Synchronizing a button class with an option control using knockoutjs

但是请求变得越来越奇怪和复杂,我开始想出越来越疯狂的方法来遍历DOM,从我所在的那一行开始,向上到达父级,向下返回到我的兄弟,然后从相邻元素中提取文本并进行其他疯狂操作。

然后我看到了那道光

我开始和一个只知道和/或住在JS的初级开发人员一起做一个项目,他只问了我一个问题。

:“如果这一切都给您带来了这么多痛苦,那么为什么不为您的行创建一个视图模型呢?”

因此,下面的代码就诞生了。

代码语言:javascript
运行
复制
var DirectoryEntryViewModel = (function ()
{
  function DirectoryEntryViewModel(inputRecord, parent)
  {
    this.Pkid = ko.observable(0);
    this.Name = ko.observable('');
    this.TelephoneNumber = ko.observable('');
    this.myParent = parent;

    ko.mapping.fromJS(inputRecord, {}, this);

  }

  DirectoryEntryViewModel.prototype.SomePublicFunction = function ()
  {
    // This is a function that will be available on every row in the array
    // You can call public functions in the base VM using "myParent.parentFunc(blah)"
    // you can pass this row to that function in the parent using  "myParent.someFunc(this)"
    // and the parent can simply do "this.array.pop(passedItem)" or simillar
  }

  return DirectoryEntryViewModel;
})();

var IndexViewModel = (function ()
{
  function IndexViewModel(targetElement)
  {
    this.loadComplete = ko.observable(false);
    this.phoneDirectory = ko.observableArray([]);
    this.showAlert = ko.computed(function ()
    {
      if (!this.loadComplete())
        return false;
      if (this.phoneDirectory().length < 1)
      {
        return true;
      }
      return false;
    }, this);

    this.showTable = ko.computed(function ()
    {
      if (!this.loadComplete())
        return false;
      if (this.phoneDirectory().length > 0)
      {
        return true;
      }
      return false;
    }, this);

    ko.applyBindings(this, targetElement);
    $.support.cors = true;
  }

  IndexViewModel.prototype.Load = function ()
  {
    var _this = this;
    $.getJSON("/module3/directory", function (data)
    {
      if (data.length > 0)
      {
        _this.phoneDirectory(ko.utils.arrayMap(data, function (item)
        {
          return new DirectoryEntryViewModel(item, _this);
        }));
      } else
      {
        _this.phoneDirectory([]);
      }
      _this.loadComplete(true);
    });
  };

  return IndexViewModel;
})();

window.onload = function ()
{
  var pageView = document.getElementById('directoryList');
  myIndexViewModel = new IndexViewModel(pageView);
  myIndexViewModel.Load();
};

现在,这并不是最好的例子(我刚刚从一个我不得不动手的项目中拉出来),但它是有效的。

是的,您必须确保在JSON中将字段添加到后端时,也要将其添加到行视图模型(可以使用RequireJS或类似工具加载),并在需要的地方将该列添加到表/列表/其他标记中。

但是为了增加一两行代码,您可以轻松地添加一个函数,然后在集合中的每一行都可以使用该函数。

而且,根据typescript的说明,上面的整个JS是由TS编译器从实现相同模式的TS源生成的。

我有相当多的东西以这种方式运行(在我的github页面上有几个例子-你可以克隆http://github.com/shawty ),我像这样运行的一些应用程序有完整的视图模型-基于计算的可观察对象中的单个简单更改来适应整个UI,我有行管理自己的状态(包括直接与数据库对话),然后在操作成功后更新父表中的状态。

希望这能给你一些思考的食粮。虽然您可能会在获取的道路上挣扎,尝试扩展现有的KO类,但老实说,我认为您会发现上面的模式更容易掌握。

我尝试了和您以前一样的方法,但是当我的JS朋友指出为行创建一个VM并重用它是多么容易之后,我很快就放弃了它。

希望它能帮助Shawty

票数 2
EN

Stack Overflow用户

发布于 2016-11-24 17:58:03

实际上你要找的是一个extends KnockoutObservableArray的类,而不是一个implements它的类。

然而,扩展需要一个实现而不是接口,而这个实现在Typescript中不可用。只有一个静态接口KnockoutObservableArrayStatic,它返回一个实现,与knockout的ko.observableArray实现非常相似。

我用favoring composition over inheritance解决了类似的问题。例如:

代码语言:javascript
运行
复制
export class Emails
{
    collection = ko.observableArray<Email>();

    //add a new email to the list
    addItem() : void
    {
        var email = new ContactEmail();
        ...
        this.collection.push(email);
    };
}

您可以访问集合属性以绑定到DOM,或者如果您需要observableArray的任何功能:

代码语言:javascript
运行
复制
<div data-bind="foreach: myEmails.collection">
...
</div>
票数 2
EN

Stack Overflow用户

发布于 2014-12-02 00:37:21

implements关键字用于声明您将实现所提供的接口...为了满足这个条件,您将需要实现以下接口中定义的所有方法(因为您需要遵循KnockoutObservableArray<T>的整个链。

或者,创建一个较小的接口来表示您从自定义类中实际需要的内容,如果它是所有这些接口的子集,那么您将能够将您的接口用于您的自定义类以及普通的KnockoutObservableArray<T>类(它将在结构上通过接口测试)。

代码语言:javascript
运行
复制
interface KnockoutObservableArray<T> extends KnockoutObservable<T[]>, KnockoutObservableArrayFunctions<T> {
    extend(requestedExtenders: { [key: string]: any; }): KnockoutObservableArray<T>;
}

interface KnockoutObservable<T> extends KnockoutSubscribable<T>, KnockoutObservableFunctions<T> {
    (): T;
    (value: T): void;

    peek(): T;
    valueHasMutated?:{(): void;};
    valueWillMutate?:{(): void;};
    extend(requestedExtenders: { [key: string]: any; }): KnockoutObservable<T>;
}

interface KnockoutObservableArrayFunctions<T> {
    // General Array functions
    indexOf(searchElement: T, fromIndex?: number): number;
    slice(start: number, end?: number): T[];
    splice(start: number): T[];
    splice(start: number, deleteCount: number, ...items: T[]): T[];
    pop(): T;
    push(...items: T[]): void;
    shift(): T;
    unshift(...items: T[]): number;
    reverse(): T[];
    sort(): void;
    sort(compareFunction: (left: T, right: T) => number): void;

    // Ko specific
    replace(oldItem: T, newItem: T): void;

    remove(item: T): T[];
    remove(removeFunction: (item: T) => boolean): T[];
    removeAll(items: T[]): T[];
    removeAll(): T[];

    destroy(item: T): void;
    destroy(destroyFunction: (item: T) => boolean): void;
    destroyAll(items: T[]): void;
    destroyAll(): void;
}

interface KnockoutSubscribable<T> extends KnockoutSubscribableFunctions<T> {
    subscribe(callback: (newValue: T) => void, target?: any, event?: string): KnockoutSubscription;
    subscribe<TEvent>(callback: (newValue: TEvent) => void, target: any, event: string): KnockoutSubscription;
    extend(requestedExtenders: { [key: string]: any; }): KnockoutSubscribable<T>;
    getSubscriptionsCount(): number;
}

interface KnockoutSubscribableFunctions<T> {
    notifySubscribers(valueToWrite?: T, event?: string): void;
}

interface KnockoutObservableFunctions<T> {
    equalityComparer(a: any, b: any): boolean;
}

这是另一种选择的一个例子。假设您需要以pushremove为例。(旁注:继承在这里是不可能的,因为这些都是接口-如果Knockout支持继承,类型定义可以更改为允许自由工作的extends,而不是这个答案的艰苦的implements版本…)

本例中有趣的部分是第一个接口-它是您定义的自定义接口,但任何与其匹配的接口都可以执行,包括KnockoutObservableArray<Email>。这是一个结构类型的例子,可以节省你的时间。结构类型想让你去酒吧。

代码语言:javascript
运行
复制
/// <reference path="scripts/typings/knockout/knockout.d.ts" />

interface MyObservableArray<T> {
    push(...items: T[]): void;
    remove(item: T): T[];
}

class Email {
    user: string;
    domain: string;
}

class ObservableEmailArray implements MyObservableArray<Email> {
    push(...items: Email[]): void {

    }

    remove(item: Email): Email[] {
        return [];
    }
}

var observableArrayOne: KnockoutObservableArray<Email> = ko.observableArray<Email>();
var observableArrayTwo: MyObservableArray<Email> = new ObservableEmailArray();

function example(input: MyObservableArray<Email>) {
    // Just an example - will accept input of type MyObservableArray<Email>...
}

example(observableArrayOne);

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

https://stackoverflow.com/questions/27230872

复制
相关文章

相似问题

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