Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/372.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript JS流:流中的继承是否被破坏?_Javascript_Inheritance_Flowtype - Fatal编程技术网

Javascript JS流:流中的继承是否被破坏?

Javascript JS流:流中的继承是否被破坏?,javascript,inheritance,flowtype,Javascript,Inheritance,Flowtype,考虑这样一种情况,您有一个从类a扩展而来的类B。您创建了一个类型B的对象,并调用了在a中定义的方法fooA,然后调用了在B中定义的方法fooB class A { fooA () { console.log('fooA called') return this } } class B extends A { fooB () { console.log('fooB called') return this } } new B().fooA().f

考虑这样一种情况,您有一个从类a扩展而来的类B。您创建了一个类型B的对象,并调用了在a中定义的方法fooA,然后调用了在B中定义的方法fooB

class A {
  fooA () {
    console.log('fooA called')
    return this
  }
}

class B extends A {
  fooB () {
    console.log('fooB called')
    return this
  }
}

new B().fooA().fooB()
运行时,代码按预期记录以下内容

fooA called
fooB called
因此Javascript理解
new B().fooA()
是类B的对象。但是,Flow给了我以下错误消息:

Cannot call new B().fooA().fooB because property fooB is missing in A
怎么办?我对一个解决方案感兴趣,在这个解决方案中,我不需要更改父类a,因为它是在npm包中定义的。但是我可以更改B。

函数fooA()返回“this”,这是“A”的一个实例。正如您所知,类A不知道方法fooB的存在。因此,Flow(正确地)指出A中缺少属性fooB

您知道,事实上,A的这个特定实例也是B的一个实例,但Flow不能推断出这一点。您必须告诉它,fooA()返回的A是使用强制转换的特定场景中B的一个实例

将调用更改为
(new B().fooA():B).fooB()
应该可以解决流错误


Javascript(sansflow)不关心这个语义。当您对fooA()返回的对象调用“fooB”时,它只是在对象中查找一个名为“fooB”的方法,该方法碰巧存在,因此它可以工作,尽管它更容易因重构而中断。Flow很有帮助,因为它迫使您了解正在抛出的类型,并在将来为您提供这些问题的编译时检查。

如果您将
fooA
方法键入为返回
this
,然后Flow理解任何扩展
A
类的类也将从方法返回自身的实例:

()

由于您不想更改
A
类:另一种简单的方法是键入
B
类的
fooA
函数以返回
B
的实例:

()


我不使用flow,但我倾向于认为它的行为是正确的。考虑到
A
是一个超类型,它不知道
B
;它只知道
这个
是一个
A
,可以是任何类型的子类型。因此,从静态类型安全的角度来看,此时的类型系统无法知道
fooA
的结果也是一个
B
实例。我不会说JavaScript“理解”任何类型。它没有内置的类型安全性,只有运行时存在的类型安全性。在编译时,它只允许您做任何您想做的事情。FWIW,将
fooA
注释为
fooA():这可以解决问题。作为一种解决方法,您可以添加一个成员
fooA:()=>B
B
类。更好的解决方案是为这个npm包提供打字。我刚刚在他们的网站上测试了他们的类型转换,他们的类型转换似乎仍然要求它是可证明安全的。我尝试了同一行代码,但仍然出现了错误。虽然:
(new B().fooA():Object.fooB()
@CrazyTrain:将值强制转换为
对象
允许您访问任何属性(即使它不存在)。它就像一个通配符。@FelixKling:是的,我想它基本上恢复为“不安全”JS。您应该发布找到的解决方案,因为它似乎描述了OP在类型系统中想要什么。@CrazyTrain:OP想要一个不需要更改
a
的解决方案。
class A {
  fooA (): this {
    console.log('fooA called')
    return this
  }
}

class B extends A {
  fooB () {
    console.log('fooB called')
    return this
  }
}

new B().fooA().fooB() // No error
class A {
  fooA () {
    console.log('fooA called')
    return this
  }
}

class B extends A {
  fooB () {
    console.log('fooB called')
    return this
  }
  fooA: () => B; // Hey Flow, this actually returns a B
}

new B().fooA().fooB() // No error!