【问题标题】:Computed is not assignable to Observable after upgrade to Knockout.js 3.5.0升级到 Knockout.js 3.5.0 后,Computed 不可分配给 Observable
【发布时间】:2019-08-10 23:08:45
【问题描述】:

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

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

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

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

Subscribable 类型,我认为它是某种“父”类型,它在声明中起作用:

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

这不会引发错误。但是没有对 value setter 执行类型检查:

x(2);    // this is wrong but no compiler error

谁能解释一下这些新的类型层次结构变化以及我们应该如何使用它?

【问题讨论】:

  • 没有computeddependantObservable 类型分配给x 吗?我不完全确定“每个计算的也是可观察的”在技术上是否正确。就像你提到的,我认为computed 的原型是subscribable,而不是observable
  • 在带有“旧”类型的 KO 3.4 中,我们成功地将 Observable 类型用作所有“更复杂”类型(如 Computed)的“母亲”类型。这个想法可以从 util 函数的淘汰文档中以某种方式得出,该文档指出:ko.isObservable - 对于可观察对象、可观察数组和所有计算的可观察对象返回 true。。在新类型中,我可以清楚地看到SubscribableObservableComputed 的父级,其子级之间没有直接关系。类型系统发生了变化有点遗憾,但是好的,我们会像往常一样适应......

标签: typescript knockout.js


【解决方案1】:

您也可以添加编译器选项

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

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

【讨论】:

    【解决方案2】:

    在 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);
    }
    

    【讨论】:

      【解决方案3】:

      我现在正在自己升级到 3.5.0。这是一个很大的变化,因为我们应该使用项目附带的类型文件,它会更改所有类的名称并摆脱全局 ko。我认为这些都是好事。我对代码的转换很满意(嗯,除了尝试通过淘汰赛验证进行编译)。

      我遇到了您遇到的确切问题。我知道当我将计算分配给可观察类型变量时,它是一个 hack,但我也知道它可以正常工作,因为接口足够接近。这次升级迫使我重新审视黑客并正确处理它。这是我现在在代码中的操作方式:

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

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

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

      【讨论】:

      • 这正是预期的工作,包括类型检查。但是恕我直言,Subscribable 类型也应该可以工作,因为据我了解,ko.Observable&lt;boolean&gt; | ko.Computed&lt;boolean&gt; 实际上等于ko.Subscribable&lt;boolean&gt;,至少在任何实际情况下都是这样。但是查看 d.ts 文件似乎有些扩展程序破坏了这一点。没有测试它。无论如何,目前这种类型的联合似乎是“正确的做法”,谢谢。
      【解决方案4】:

      你可以像这样使用KnockoutComputed&lt;T&gt;

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

      【讨论】:

      • 谢谢,但 KnockoutComputed 类型来自@types/knockout 定义,适用于 v3.4。然而,npm 上的 v3.5 有它自己的定义,它们的“组织”方式不同。我正在寻求“新”类型系统的帮助,因为在 v3.4 类型系统中,使用 const x: KnockoutObservable&lt;boolean&gt; = ko.computed(() =&gt; true); 是完全可以的,这很棒,并且支持 observable 是所有其他复杂变体的超类型(如计算变体)的想法跨度>
      • @TomHANAX 但是@types/knockout 最新版本是3.4.64 根据:npmjs.com/package/@types/knockout
      猜你喜欢
      • 2020-04-27
      • 1970-01-01
      • 2016-09-10
      • 2018-08-30
      • 1970-01-01
      • 2023-04-10
      • 2020-11-23
      • 2020-04-17
      • 2019-01-12
      相关资源
      最近更新 更多