在您给出的示例中,您正在查看从联合类型到其成员之一的“强制转换”。虽然通常将其视为强制转换,但它与其他语言中的类型转换不同。
通过将foo 的类型设置为string | number,我们告诉Flow 该值可以是字符串或数字。然后我们碰巧在其中放入了一个字符串,但 Flow 并没有因此而放弃我们对其类型的直接断言,即使在以后无法更改的情况下(例如这种情况)也是如此。
要将其分配给 string 类型的变量,Flow 需要知道即使它可能是 string 或 number,在我们进行分配时,我们确信它只能成为string。
这种减少可能选项的过程称为类型细化。
类型优化
要细化类型,我们需要证明它一定是我们所说的类型,以 Flow 理解的方式。
在原始示例中,您可以使用typeof:
type StringOrNumber = string | number
const foo: StringOrNumber = 'hello'
// This would raise an error here:
// const bar: string = foo
if (typeof foo === "string") {
// Flow now knows that foo must be a string, and allows this.
const bar: string = foo
}
Flow 无法理解人类可以看到的类型细化的所有内容,因此有时您需要查看 the refinement docs 以了解什么可能使 Flow 理解它。
抑制 cmets
有时无法表达对 Flow 的改进的安全性。我们可以通过使用suppression comment 来强制 Flow 接受一个语句,这将抑制 Flow 否则会报告的错误。默认抑制注释为$FlowFixMe,但可以配置为不同的注释或cmets。
Flow会在第二行报错,报告unionValue可能是'number'类型:
const unionValue: StringOrNumber = 'seven'
const stringValue: string = unionValue
但是,通过使用抑制注释,这会通过 Flow:
const unionValue: StringOrNumber = 'seven'
// $FlowFixMe: We can plainly see this is a string!
const stringValue: string = unionValue
抑制 cmets 的一个有用功能是,一个没有跟随错误的抑制注释被认为是一个错误。如果我们改变示例中的类型:
const unionValue: string = 'seven'
// $FlowFixMe: Even though this is a string, suppress it
const stringValue: string = unionValue
现在 Flow 会改为报告“未使用的抑制”错误,提醒我们。这在 Flow 应该能够识别细化但不能识别时特别有用 - 通过使用抑制注释,如果未来版本的 Flow 将代码识别为类型安全。
任意投射
如果你真的不能以一种可以证明其安全流动的方式来表达它,并且你不能(或不会)使用抑制注释,你可以将任何类型转换为 any 和 @987654336 @任何类型:
const unionValue: StringOrNumber = 'seven'
// Flow will be okay with this:
const stringValue: string = (unionValue: any)
通过将值转换为any,我们要求 Flow 忘记它所知道的关于值类型的任何信息,并假设我们对它所做的任何事情都必须是正确的。如果我们稍后将其放入类型变量中,Flow 将假定这一定是正确的。
注意事项
请务必注意,抑制 cmet 和强制转换 any 都是不安全的。它们完全覆盖 Flow,并且会愉快地执行完全无意义的“强制转换”:
const notAString: {key: string, key2: number} = {key: 'value', key2: 123}
// This isn't right, but Flow won't complain:
const stringValue: string = (notAString: any)
在这个例子中,stringValue 持有来自notAString 的object,但 Flow 确定它是一个字符串。
为避免这种情况,请尽可能使用 Flow 理解的改进,并避免使用其他不安全的“强制转换”技术。