流程:形状类型和其他可选字段

Flow: shape types and additional optional fields

我经常发现自己需要做以下事情,而 Flow 让它变得非常困难:

/* @flow */

type Foo = {
  +foo?: number,
}

type FooBar = {
  +foo?: number,
  +bar?: number,
}

const foo: Foo = {foo: 2}

function process(arg: $ReadOnly<FooBar>) {
}

process(foo)

请问有什么好的方法吗?我收到以下错误:

17: process(foo)
            ^ Cannot call `process` with `foo` bound to `arg` because property `bar` is missing in `Foo` [1] but exists in `FooBar` [2].
References:
12: const foo: Foo = {foo: 2}
               ^ [1]
14: function process(arg: $ReadOnly<FooBar>) {
                                    ^ [2]

Flow 默认对象类型不准确;这意味着,尽管 Foo 仅被声明为显式具有单个(可选)属性 foo 类型 number,但理论上 Foo 类型的变量可以有额外的属性。例如,Foo 类型的变量可能有 属性 bar。而且,由于 bar 未键入 Foo,因此 bar 的类型不受限制(即不一定是 number)。因此,如果您要与 process 中的 arg.bar 进行交互,并且 Flow 允许 arg 属于 Foo 类型,则无法保证您会与 number。因此,流抱怨。

解决这个问题的一种方法是使用精确的对象类型。如果 Flow 知道类型 Foo 的变量永远不会有 bar 属性,那么它可以安全地传递到 process。因此,您可以将 Foo 输入为:

type Foo = {|
  +foo?: number,
|};

Try Flow

(注意:$ReadOnly 实用程序类型对于上面的 Foo 定义和 FooBar 的原始定义不是必需的,因为 bar 是不可写的。虽然,当然,保持 $ReadOnly 没问题。)