现在我正在使用Apollo Codegen生成的Flow类型。这是非常有用的工具,但所有类型都是“可能”的。现在我有下一个问题:请考虑非常简化和简单的例子(链接到Flow try):
/* @flow */
type Type1 = {| // <- example of Flow-type generated by Apollo Codegen
prop?: ?string
|}
type Type2 = { // <- example of my Flow-type
prop: string
}
function bar(y: Type2): void {
console.log(y.prop)
}
function foo(x: Type1): void {
if (x && x.prop && typeof x.prop === 'string') { // <- I'm trying to check the "x" argument
bar(x)
}
}
foo({ prop: 'hello' })
由于null
或undefined
,Flow无法理解我的检查并显示错误。如何管理?
这不能作为类型细化的原因是你的支票可以传递给Type1
和Type2
。 Flow执行条件检查,但检查可以传递Type1
的值,因此条件根本不会改进x
的类型。然后在条件内,它看到你试图将Type1
的值传递给Type2
。
要理解Flow的类型细化,重要的是要记住Flow不会对除变量类型之外的变量携带额外的细化数据。 Here是一个类似于你的例子,但没有可选字段。在valid
函数中,我们检查y.field
的类型,然后在我们知道它的类型后使用y.field
。在invalid
函数中,我们检查y.field
的类型,然后尝试使用y
。但是类型细化并没有改变y
的类型,只有y.field
,所以我们得到一个类型错误。
作为一个对应点,here是一个例子,我们根据字段的值进行类型细化。值得注意的是,在f
函数内部,变量z
具有Baz | Qux
类型,并且我们的细化是在这两者之间不重叠的场上。在这种情况下,细化将类型Baz | Qux
转换为类型Baz
,我们可以无错误地调用我们的第二个函数。
为了解决这种局限,我们需要细分值x
并将我们正在提炼的字段放入自己的变量中。然后,一旦我们知道了这个变量的类型,我们就会创建一个我们知道的类型为Type2
的值,并将其传递给所需的函数。 Here是最直接的方式。
因为这种事情经常出现,我有一种创建“转换”功能的模式,可以将潜在的不干净数据转换为干净的数据,这样其他功能就不必为复杂的复杂性而烦恼。在这种情况下,我会这样做this。
当清理深层嵌套数据或将嵌套对象从类型mixed
转换为已知类型时,这种分解转换函数的模式也非常有用。通过组合小类型的转换对象而不是从头开始编写转换对象,更容易为大类型创建转换函数。
在这个例子中,你正在改进属性prop
的类型,你不是在改进x
。流程中的细化只能用于顶级类型。有关其他策略,请参阅this question。