考虑从类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。
答案 0 :(得分:1)
如果键入fooA
方法作为返回this
,则Flow会理解扩展A
类的任何类也将从该方法返回自己的实例:
(Try)
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
由于您不想更改A
类:另一种简单的方法是键入fooA
类的B
函数以返回实例B
:
(Try)
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!
答案 1 :(得分:0)
函数fooA()返回“this”,它是“A”的一个实例。如您所知,A类不知道方法fooB存在。因此,Flow(正确地)指出A中缺少属性fooB。
您知道实际上,A的这个特定实例也是B的实例,但Flow无法推断出这一点。你必须告诉它fooA()返回的A是使用强制转换的特定场景中的B实例。
将呼叫更改为(new B().fooA(): B).fooB()
应解决Flow错误。
Javascript(sans Flow)并不关心这种语义。当你在fooA()返回的对象上调用“fooB”时,它只是在对象中寻找一个名为“fooB”的方法,它恰好存在,所以它有效,尽管它更容易破坏重构。流程很有用,因为它会强制您了解被抛出的类型,并在将来为这些问题提供编译时检查。