knockout.js 为什么这个多态赋值在Knockout中的类型化observableArray中不起作用?

5f0d552i  于 2022-11-10  发布在  其他
关注(0)|答案(1)|浏览(180)

让我们有类A和子类B。我想把一个B的数组赋给A的数组。对于普通数组,它可以正常工作,但是对于ko.ObservableArray,它失败了。

import ko from "knockout";

class A {};
class B extends A {b = 1};

const a: A = new B();                // no problem here
const aArr: A[] = [] as B[];         // no problem here
// COMPILER PROBLEM ON LAST LINE!
const aObs: ko.ObservableArray<A> = ko.observableArray() as ko.ObservableArray<B>;

编译器对最后一行不满意,它显示这样的错误:

Type 'ObservableArray<B>' is not assignable to type 'ObservableArray<A>'.
  Types of parameters 'value' and 'value' are incompatible.
    Type 'A[] | null | undefined' is not assignable to type 'B[] | null | undefined'.
      Type 'A[]' is not assignable to type 'B[]'.
        Type 'A' is not assignable to type 'B'.

但是很明显,我不想把A赋给B,而是把B赋给A
如何科普呢?

dxxyhpgq

dxxyhpgq1#

问题是ObservableArray<T>是它的类型变量T上的contravariant,这就是为什么它试图反向赋值。
虽然你可以自由地将B赋值给A(因为B extends A和你甚至不必将它声明为extends),当它进入协变位置时:

class A { }
class B { b = 1 }

const a: A = new B();
const aArr: A[] = [] as B[];

playground link
您不能指定以相同方向的这些类型参数为参数的函数。只能指定相反方向的参数。

type Fn<T> = (t: T) => void

const fn1: Fn<A> = null as unknown as Fn<B> // error here
const fn2: Fn<B> = null as unknown as Fn<A> // no error

playground link
如果你确信赋值是正确的,编译器会对你进行不必要的限制,你可以自己承担责任,把它类型转换为期望的类型:

import ko, { ObservableArray } from 'knockout'

class A {};
class B extends A {b = 1};

const bObs: ObservableArray<B> = ko.observableArray()
const aObs: ObservableArray<A> = bObs as unknown as ObservableArray<A>;

playground link
你也可以用--strictFunctionTypes选项全局关闭fn参数的逆变检查,尽管大多数时候这是非常有用的检查。

相关问题