从Javascript转换为Typescript,Knockout和DevExtreme控件

时间:2017-07-11 21:00:37

标签: typescript knockout.js devextreme

我有一些问题从Javascript转换为Typescript,特别是创建了一个devextreme控件。

在过去,我会使用以下内容在我的viewmodel中为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;});
}
...

这给了我一个错误类型KnockoutComputed不能分配给boolean类型,这很公平,我明白了。

但问题是如何做到这一点?

我可以用这个:

myButton: any; 

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

这可以工作,去打字稿的原因之一就是使用webpack等东西,所以这不是完全丢失,我只是想知道如何正确地做到这一点。

提前致谢。

1 个答案:

答案 0 :(得分:2)

我已检查过使用knockout-decoratorsknockout-es5解决问题的可能性。但是我认为最简洁的方法是简单地使用任何作为窗口小部件选项的类型。

两个示例的模板都是相同的:

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

使用knockout-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++;
    }
}

使用knockout-decorators

此方法需要单独创建计算属性(作为viewModel的一部分)。它也需要&#34; hack&#34;将计算属性的getter复制到widget选项:

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<T> | KncokoutComputed<T>,所以最清洁的&#34;对我而言 - 使用任何

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++;
    }
}