Flow 会引发错误,因为它认为您可能会改变数组:
// given the definitions of `Node`, `ANode`, and `BNode` from the question’s second example
function getFirstNodeType(nodes: Array<Node>): string {
const bNode: BNode = {type: 'b', count: 0}
// Mutate the parameter `nodes`. Adding a `BNode` is valid according its type.
nodes.push(bNode);
return nodes[0].type;
}
const nodesSubtype: Array<ANode> = [{type: 'a', value: 'foo'}];
getFirstNodeType(nodesSubtype); // error
Try Flow demo https://flow.org/try/#0C4TwDgpgBAggcgewCbQLxQN6kgLigcgEN8AaKAN0IBsBXCPAZ2ACcBLAOwHMBfAbgChs0AEKIUUdFnD0CAI1JQAxghrtgedjQC2siMz79B0qGLSxTUAD5RRyCAP4AzVYuCsE7KJwjAAYq2YmUwAVaQAKdjsGPBhmZkIQAB5TAD4ASkYWDk5Mfih8pQ8mKFlTPFtxSSE8fHkyZVV1KAAGbjyCgHoOqABZGmBCYGhgAAtoMEJ4rR89KAADSJQGOYA6WCQkbKhCeYqIOahWBgpqViRtxWVmTa5D4GOhFfb8xYgGFbAaBhGw0rs0gQFKDPKDMHw0ZieV4MADazQAuishAI2vxlOxitCAMo0WTVWBxBKJeB2FISKAwqS4AjEMiUWgyfCOBAIfDceECbx+AJBOyhSARKI4vHSAFQLpQPTMBDMIA
运行上面的代码后,nodesSubtype
将包含一个BNode
即使它被声明为数组ANode
,违反其类型。
有两种解决方案可以让 Flow 相信您不会改变数组。最明显的就是replace Array
withFlow 实用程序类型$ReadOnlyArray https://flow.org/en/docs/types/arrays/#toc-readonlyarray.
function getFirstNodeType(nodes: $ReadOnlyArray<Node>): string { // use $ReadOnlyArray
return nodes[0].type;
}
const nodesSubtype: Array<ANode> = [{type: 'a', value: 'foo'}];
getFirstNodeType(nodesSubtype); // no error
Try Flow demo https://flow.org/try/#0C4TwDgpgBAggcgewCbQLxQN6kgLigcgEN8AaKAN0IBsBXCPAZ2ACcBLAOwHMBfAbgChs0AEKIUUdFnD0CAI1JQAxghrtgedjQC2siMz79B0qGLSxTUAD5RRyCAP4AzVYuCsE7KJwjAAYq2YmUwAVaQAKdjsGPAASACUIQiQAeXYqEBhmZkIQAB5TAD4ASkYWDk5MKAB6KqgaBmh4xJS0jKyc-iguqGYfGmZPSJQGAG0ABgBdADohAW5DZXYmKCGIBgBlGlkhPEzsvPg7AokoEalcAmIySloZfEcEBHxuCYFvPwCgu1DICKjN7bSIq8aq1SJQPTMBDMIA
您只需在函数参数的类型中进行替换(例如nodes
),但如果你喜欢你可以使用$ReadOnlyArray
它适用于任何地方(例如nodesSubtype
).
$ReadOnlyArray
是最类型安全的解决方案,但您可能不希望必须更改所有现有函数才能使用它。在这种情况下,您的替代方法是通过转换数组类型any
反而。是的,你可以从一开始就这样做,但至少现在你知道why进行此转换是安全的。您甚至可以留下评论来解释为什么存在这种转换,这可能会帮助您发现不再有效的假设。
function getFirstNodeType(nodes: Array<Node>): string {
return nodes[0].type;
}
const nodesSubtype: Array<ANode> = [{type: 'a', value: 'foo'}];
// casting `Array<ANode>` to `Array<Node>` is okay because we know that `getFirstNodeType` won’t actually modify the array
getFirstNodeType(((nodesSubtype: any): Array<Node>));
Try Flow demo https://flow.org/try/#0C4TwDgpgBAggcgewCbQLxQN6kgLigcgEN8AaKAN0IBsBXCPAZ2ACcBLAOwHMBfAbgChs0AEKIUUdFnD0CAI1JQAxghrtgedjQC2siMz79B0qGLSxTUAD5RRyCAP4AzVYuCsE7KJwjAAYq2YmUwAVaQAKdjsGPBhmZkIQAB5TAD4ASkYWDk5Mfih8qGYfGmZPSJQGAG0ABgBdADohAW5DZXYmKHKIBgBlGlkhGLiExPg7FIkoSqlcAmIySloZfEcEBHxuWoEAem2lQiZsqAADWPiksZQU46hgBBOzkdSb1gYoBABrBKhdRUIaBjQADu0A+kSBtwAFoRgCdvH4AkE7KFIDcgR5AJgEsMIrho1CoICgWmQrEchOAkOghGGIH48P8gWAIXCYQiUT6A2keEI7BAGVgNOS4zSaV4QA
如果您不关心记录问题,则可以省略注释并仅投射到any
:
getFirstNodeType((nodesSubtype: any));
Try Flow demo https://flow.org/try/#0C4TwDgpgBAggcgewCbQLxQN6kgLigcgEN8AaKAN0IBsBXCPAZ2ACcBLAOwHMBfAbgChs0AEKIUUdFnD0CAI1JQAxghrtgedjQC2siMz79B0qGLSxTUAD5RRyCAP4AzVYuCsE7KJwjAAYq2YmUwAVaQAKdjsGPBhmZkIQAB5TAD4ASkYWDk5Mfih8qGYfGmZPSJQGAG0ABgBdADohAW5DZXYmKHKIBgBlGlkhGLiExPg7FIkoSqlcAmIySloZfEcEBHxuWoFvPwCgu1DIMIiovoHpPEJ2EDS03iA
其他资源
-
$ReadOnlyArray
became 有记录的 https://flow.org/en/docs/types/arrays/#toc-readonlyarray2018 年 8 月,感谢这个拉取请求 https://github.com/facebook/flow/pull/6595.
- 较旧的文章“Flow 是最好的秘密” https://medium.com/@forbeslindesay/covariance-and-contravariance-c3b43d805611描述了第三种可能的解决方法,涉及将函数的数组类型包装在泛型类型中。