简体   繁体   English

JS Flow:流程中的继承是否破裂?

[英]JS Flow: Is inheritance in Flow broken?

Consider a situation where you have a class B extending from class A. You create an object of type B and call a method fooA defined in A and then a method fooB defined in B. 考虑一种情况,你有一个B类从A类扩展。你创建一个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()

When run, the code logs the following as expected 运行时,代码按预期记录以下内容

fooA called
fooB called

So Javascript understands that new B().fooA() is an object of class B. However Flow gives me the following error message: 所以Javascript理解new B().fooA()是类B的对象。但是Flow给出了以下错误消息:

Cannot call new B().fooA().fooB because property fooB is missing in A

What to do? 该怎么办? I'm interested in a solution where I do not need to change the parent class A because it is defined in an npm package. 我对一个解决方案感兴趣,我不需要更改父类A,因为它是在npm包中定义的。 I can change B though. 我可以改变B。

If you type the fooA method as returning this , then Flow understands that any classes that extend the A class will also return an instance of themselves from the method: 如果你输入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

Since you don't want to change the A class: another easy way to get this working is to type the fooA function of B class to return an instance of B : 因为您不想更改A类:另一种简单的方法是键入B类的fooA函数以返回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!

The function fooA() returns "this" which is an instance of "A". 函数fooA()返回“this”,它是“A”的一个实例。 As you know, the class A has no idea that the method fooB exists. 如您所知,A类不知道方法fooB存在。 Therefore, Flow (rightfully) points out that the property fooB is missing in A. 因此,Flow(正确地)指出A中缺少属性fooB。

You have the knowledge that in fact, this particular instance of A is also an instance of B, but Flow can't infer that. 知道事实上,A的这个特定实例也是B的实例,但Flow无法推断出这一点。 You have to tell it that the A returned by fooA() is an instance of B in this specific scenario using casting. 你必须告诉它fooA()返回的A是使用强制转换的特定场景中的B实例。

Changing your call to (new B().fooA(): B).fooB() should resolve the Flow error. 将您的调用更改为(new B().fooA(): B).fooB()应解决Flow错误。

Javascript (sans Flow) doesn't care about this semantic. Javascript(sans Flow)并不关心这种语义。 When you call "fooB" on the object returned by fooA() it just looks for a method called "fooB" in the object, which happens to exist, so it works, although it is more prone to breaking with refactor. 当你在fooA()返回的对象上调用“fooB”时,它只是在对象中寻找一个名为“fooB”的方法,它恰好存在,所以它有效,尽管它更容易破坏重构。 Flow is helpful because it forces you stay cognizant of what types are being thrown around and gives you compile-time checks for these problems in the future. 流是有用的,因为它会强制您了解被抛出的类型,并在将来为这些问题提供编译时检查。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM