【问题标题】:Converting from Javascript to Typescript, Knockout and DevExtreme controls从 Javascript 转换为 Typescript、Knockout 和 DevExtreme 控件
【发布时间】:2017-07-11 21:00:36
【问题描述】:

我在从 Javascript 转换为 Typescript 时遇到了一些问题,尤其是在创建 devextreme 控件时。

过去我会在我的视图模型中为 devextreme 控件创建一个对象,使用如下:

self.myButton = {
  text: 'Click Me',
  disabled: ko.purecomputed(function(){ return self.myobservable().length>0;});
}

效果很好,在我试过的打字稿中......

myButton: DevExpress.ui.dxButtonOptions;

然后在构造函数中...

....
self.myButton = {
  text: 'Click Me',
  disabled: ko.purecomputed(function(){ return self.myobservable().length>0;});
}
...

这给了我一个错误 Type KnockoutComputed is not assignable to type boolean,这很公平,我明白了。

但问题是这应该怎么做呢?

我可以用这个:

myButton: any; 

在按钮选项的声明中,但我认为这有点违背了使用打字稿的目的??

这可以工作,使用 typescript 的原因之一是还要使用 webpack 之类的东西,所以这不是完全的损失,我只是想知道如何正确地做到这一点。

提前致谢。

【问题讨论】:

  • 一个想法:你可以尝试使用keyof并扩展DevExpress接口以将KnockoutComputed<T> & T作为值。
  • 作为一个选项,您可以将knockout-decorator 用于您的属性。在这种情况下,属性将具有简单类型并且可以用于 DevExtreme 的选项。
  • @unional 你能给我任何关于如何在 devexpress 界面中使用 keyof 的例子吗,我是 typescript 的新手,所以不知道从哪里开始?
  • @mykhailo.romaniuk 感谢您提供此链接,我从未见过此链接,但它看起来确实不错。但是有一个问题,如果我要这样做,我是否必须将我的 pureComputed 分解为 vm 的单独方法?
  • @JasonColey 我和knockout-decorators 玩了一会儿,似乎他们无法解决您的问题。我也有过使用knockout-es5 的想法,但是对于您使用此库的问题的所有解决方案对我来说也都是解决方法。我不得不说,我没有看到比使用 any 小部件选项更好的方法

标签: typescript knockout.js devextreme


【解决方案1】:

我已经检查了使用knockout-decoratorsknockout-es5 来解决您的问题的可能性。但是我认为最简洁的方法是简单地使用 any 作为小部件选项的类型。

两个示例的模板相同:

<div data-bind="dxButton: buttonOptions"></div>

使用淘汰赛-es5

这种方法需要单独创建计算属性。这个属性的创建不是很好的类型,所以我们在这里失去了一些强类型的好处。

// importing thing from DevExtreme.
import "devextreme/ui/button";
import DevExpress from "devextreme/bundles/dx.all";

import * as ko from "knockout";
// importing knockout-es5 to include track and defineProperty functionality
import "knockout-es5";

// This small util will make creation of compute a bit more strong by using keyof
const createComputed = <T>(prototype: T, key: keyof T, computedFunc: Function): void => {
    ko.defineProperty(prototype, key, computedFunc);
}

class DevextremeTestViewModel {
    clickCounter: number = 0;
    buttonOptions: DevExpress.ui.dxButtonOptions;

    constructor() {
        this.buttonOptions = {
            text: "Start",
            onClick: this.increaseCounter
        };

        // start tracking clickCounter property (make it observable)
        ko.track(this, ["clickCounter"]);

        // assign to text property of widget options computed value
        createComputed(this.buttonOptions, "text", () => {
            return `Clicked ${this.clickCounter} times`;
        });
    }

    increaseCounter(): void {
        this.clickCounter++;
    }
}

使用敲除装饰器

这种方法需要单独创建计算属性(作为 viewModel 的一部分)。此外,将计算属性的 getter 复制到小部件选项也需要“破解”:

import "devextreme/ui/button";
import DevExpress from "devextreme/bundles/dx.all";
// include required decorators
import { observable, computed } from "knockout-decorators";

// Magic function to copy getter from one property to another
const copyGetter = <T, TProp>(prototype: T, key: keyof T, propProto: TProp, propertyKey: keyof TProp) => {
    let getter = Object.getOwnPropertyDescriptor(propProto, propertyKey).get;
    Object.defineProperty(prototype, key, {
        get: getter
    });
}

class DevextremeTestViewModel {
    // Create observable
    @observable clickCounter: number = 0;
    // Create computed that based on observable
    @computed({ pure: true }) get buttonText(): string {
        return `Clicked ${this.clickCounter} times`;
    };
    buttonOptions: DevExpress.ui.dxButtonOptions;

    constructor() {
        this.buttonOptions = {
            text: this.buttonText,
            onClick: this.increaseCounter
        };

        // Need to copy getter from our computed to options property.
        copyGetter(this.buttonOptions, "text", this, "buttonText");
    }

    increaseCounter(): void {
        this.clickCounter++;
    }
}

使用任意

正如我所说,由于我们不能强制 DevExtreme 团队更改小部件选项的界面以支持 T | KnockoutObservable&lt;T&gt; | KncokoutComputed&lt;T&gt;,因此对我来说最“干净”的方式 - 使用 any

import "devextreme/ui/button";
import DevExpress from "devextreme/bundles/dx.all";
import { observable, computed } from "knockout-decorators";
import * as ko from "knockout";

class DevextremeTestViewModel {
    // Create observable
    @observable clickCounter: number = 0;
    buttonOptions: any = {
        text: ko.pureComputed(()=> {
            return `Clicked ${this.clickCounter} times`;
        }),
        onClick: this.increaseCounter
    };

    increaseCounter(): void {
        this.clickCounter++;
    }
}

【讨论】:

    猜你喜欢
    • 2022-11-03
    • 1970-01-01
    • 1970-01-01
    • 2021-12-24
    • 2016-11-18
    • 2020-10-04
    • 2023-02-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多