升级到 Knockout.js 3.5.0 后,Computed 不可分配给 Observable

Computed is not assignable to Observable after upgrade to Knockout.js 3.5.0

Knockout.js 3.5.0 在 npm 上带有它自己的类型定义。 让我们将此变量 x 定义为:

const x: ko.Observable<boolean> = ko.computed(() => true);

现在我们得到了编译器错误: 类型 'Computed' 缺少类型 'Observable' 的以下属性:valueHasMutated、valueWillMutate

我明白编译器试图告诉我什么,但我认为这主要是错误的——因为每个计算的也是一个可观察的。此行为在 3.4.x 上运行良好,使用来自 @types/knockout.

的类型定义

Subscribable 类型,我认为是某种 "parent" 类型,它在声明中起作用:

const x: ko.Subscribable<boolean> = ko.computed(() => true);

这不会引发任何错误。但是,不对值 setter:

执行类型检查
x(2);    // this is wrong but no compiler error

任何人都可以阐明这些新的类型层次结构变化以及我们应该如何使用它吗?

您可以这样使用 KnockoutComputed<T>

const x: KnockoutComputed<boolean> = ko.computed(() => true);

或者您可以添加编译器选项

"path" {
   ...
   "knockout": [ "node_modules/@types/knockout" ],
   ...
}

这样您就可以使用旧的 KO 类型,直到找到更好的升级代码的方法

我现在正在升级到 3.5.0。这是一个很大的变化,因为我们应该使用项目附带的类型文件,它会更改 类 的所有名称并删除全局 ko。我认为这些都是好事。我对我的代码的 t运行 形式很满意(好吧,除了试图让 knockout-validation 编译)。

我 运行 进入的正是你 运行 进入的问题。我知道,当我将一个计算值分配给一个可观察类型变量时,这是一种 hack,但我也知道它会工作得很好,因为接口足够接近。这次升级迫使我重新审视黑客并妥善处理它。这是我现在在我的代码中的做法:

我知道将变量定义为接受可观察值或计算值的变量:

class SomeClass {
   public value: Observable<boolean> | Computed<boolean>;
}

这允许所有其他可能正在阅读代码的开发人员认为该值可能是一个计算值,因此他们不应该只是盲目地为其分配一个值。

在 Knockout 3.5.1 中,我能够引用 Knockout 包中定义的接口 PureComputed

import * as ko from 'knockout';
import { Computed, PureComputed, Observable } from 'knockout';

class MyClass
  originalComments: string;
  comments: Observable<string>;

  constructor(serverData: any) {
    this.originalComments = serverData.comments || '';
    this.comments = ko.observable(this.originalComments);
  }

  hasChanged: PureComputed<boolean> = ko.pureComputed(() => this.comments() !==  this.originalComments);
}