我已经检查了使用knockout-decorators 和knockout-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<T> | KncokoutComputed<T>,因此对我来说最“干净”的方式 - 使用 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++;
}
}