Javascript JS流:流中的继承是否被破坏?
考虑这样一种情况,您有一个从类a扩展而来的类B。您创建了一个类型B的对象,并调用了在a中定义的方法fooA,然后调用了在B中定义的方法fooBJavascript 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
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!