我有一个类型的值Array<A>(子类型数组)。 Flow 不允许我将其传递到期望的地方Array<A | B>(一组超类型),尽管它显然有效。

例如,我无法用 type 赋值Array<'left' | 'right'>到一个类型为的变量Array<string>:

const directions: Array<'left' | 'right'> = ['right', 'left'];
const messages: Array<string> = directions; // error

出现此错误:

2: const messages: Array<string> = directions; // error
                                   ^ Cannot assign `directions` to `messages` because in array element: Either string [1] is incompatible with string literal `left` [2]. Or string [1] is incompatible with string literal `right` [3].
    References:
    2: const messages: Array<string> = directions; // error
                             ^ [1]
    1: const directions: Array<'left' | 'right'> = ['right', 'left'];
                               ^ [2]
    1: const directions: Array<'left' | 'right'> = ['right', 'left'];
                                        ^ [3]

Try Flow demo https://flow.org/try/#0MYewdgzgLgBAJgSwE4FNhQeCAuGBBJJAQwE8AeAcgBsUAzKCmAHxgqQQHMALBgPhgC8MANptOPCgBpWNehQC6AbgBQoSLAC2KCBCIdtuAsXLR2YDvyGJU6TJEUwA9I5gpCIJEA

同样,我也无法通过Array<ANode>到一个需要的函数Array<Node>, 虽然Node is ANode | BNode:

type ANode = {type: 'a', value: string};
type BNode = {type: 'b', count: number};

type Node = ANode | BNode;

function getFirstNodeType(nodes: Array<Node>): string {
    return nodes[0].type;
}

// works
const nodesSupertype: Array<Node> = [{type: 'a', value: 'foo'}];
getFirstNodeType(nodesSupertype);

// error
const nodesSubtype: Array<ANode> = [{type: 'a', value: 'foo'}];
getFirstNodeType(nodesSubtype); // error
16: getFirstNodeType(nodesSubtype); // error
                    ^ Cannot call `getFirstNodeType` with `nodesSubtype` bound to `nodes` because property `value` is missing in `BNode` [1] but exists in `ANode` [2] in array element.
References:
6: function getFirstNodeType(nodes: Array<Node>): string {
                                            ^ [1]
15: const nodesSubtype: Array<ANode> = [{type: 'a', value: 'foo'}];
                                ^ [2]

16: getFirstNodeType(nodesSubtype); // error
                    ^ Cannot call `getFirstNodeType` with `nodesSubtype` bound to `nodes` because string literal `a` [1] is incompatible with string literal `b` [2] in property `type` of array element.
References:
1: type ANode = {type: 'a', value: string};
                        ^ [1]
2: type BNode = {type: 'b', count: number};
                        ^ [2]

Try Flow demo https://flow.org/try/#0C4TwDgpgBAggcgewCbQLxQN6kgLigcgEN8AaKAN0IBsBXCPAZ2ACcBLAOwHMBfAbgChs0AEKIUUdFnD0CAI1JQAxghrtgedjQC2siMz79B0qGLSxTUAD5RRyCAP4AzVYuCsE7KJwjAAYq2YmUwAVaQAKdjsGPBhmZkIQAB5TAD4ASkYWDk5Mfih8qGYfGmZPSJQGAG0ABgBdADohAW5DAHpWqAB3BGYAawZ+ZXYmKHKIBgBlGkhmIRi4hOS7FIkoSqlcAmIySloZfEcEBHxuWoFvPwCgu1DICKipmaE0h3aoPWYewY8RscmaWRzWALJLwZardZAogKXZ0PAHI4nM78C7+QLAELhP5TQHSF5QN4fHpAA


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描述了第三种可能的解决方法,涉及将函数的数组类型包装在泛型类型中。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

随机推荐

  • 在尾递归函数中使用管道时出现堆栈溢出异常

    我有一个简单的游戏循环实现 let gameLoop gamestate let rec innerLoop prev gamestate let now getTicks let delta now prev gamestate gt r
  • \363\353\377\377\377\177 是什么?

    gdb p char 0x7fffffffe9c8 16 0x7fffffffe9c8 363 353 377 377 377 177 它看起来不像ascii 也不像多字节 那是什么 这些都是octal http en wikipedia
  • 如何改变PCM数据流的音量(实验失败)

    Solved 我的代码以前从未用于处理有符号值 因此字节 gt 短转换错误地处理了符号位 这样做正确地解决了问题 问题是 我正在尝试更改 PCM 数据流的音量 我可以从立体声文件中提取单通道数据 通过跳过 复制它们 插入零 等方式对样本进行
  • iOS 6 无法自动旋转

    在我维护的应用程序中 在纵向和纵向颠倒模式下应该发生旋转 所有旋转均在摘要面板中启用 BOOL shouldAutorotateToInterfaceOrientation UIInterfaceOrientation interfaceO
  • R中多个列表的元素均值

    我有十个巨大的列表 每个列表有七个元素 但元素很大 我需要计算这些列表的元素平均值 那么如果有A1 A2 A3 A10列表 我需要计算 mean1 mean A1 1 A2 1 A3 1 A10 1 mean7 mean A1 7 A2 7
  • 通过 ContentValues 将时间戳插入数据库

    在Android中 是否可以使用以下命令将时间戳插入数据库中ContentValues 当我尝试使用这样的方法添加它时 ContentValues args new ContentValues args put MY DATE my dat
  • 使用 C++ 用户定义的文字来初始化数组

    我有一堆测试向量 以十六进制字符串的形式呈现 MSG 6BC1BEE22E409F96E93D7E117393172A MAC 070A16B46B4D4144F79BDD9DD04A287C MSG 6BC1BEE22E409F96E93
  • 从同一个 onclick 调用两个函数[重复]

    这个问题在这里已经有答案了 HTML 和 JavaScript 如何从一个 onclick 事件调用 2 个函数 这是我的代码
  • .CSHTML 中的 Visual Studio 2010 代码格式 - 缩进不正确

    需要解释的问题非常简单 在 Visual Studio 2010 SP1 中 我在使用 Razor 时发现大括号出现奇怪的缩进问题 它看起来是这样的 div div div div if true b Hi b div div div di
  • Authorize.net 支付集成 [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我正在寻找使用 PHP 与网站进行 Authorize net 支付集成 我的问题是 1 我可以在哪里找到使用 PHP 执行此操作的教程 开发指南和
  • 在 Clojure 中查找与谓词匹配的元素的索引?

    使用 Clojure 如何找到该向量中第一个具有正值的索引 1 0 3 7 9 我知道你可以相当优雅地得到第一个结果first and filter first filter pos 1 0 99 100 101 这段代码返回值99 我想要
  • 如何在 Haskell 中指定多播套接字的本地绑定接口?

    我已经尝试过 Network Multicast 包并且它确实有效 但是 我找不到为多播套接字指定本地绑定接口 bond0 或 bond1 等 的方法 我知道在C中我需要使用ioctl将键转换为struct sockaddr in 然后将该
  • 当你初始化一个没有构造函数的类时,会调用什么? [复制]

    这个问题在这里已经有答案了 因此 当一个类具有私有构造函数时 您无法初始化它 但当它没有构造函数时 您可以初始化它 那么 当你初始化一个没有构造函数的类时 会调用什么呢 例如 这里叫什么 new b public class a publi
  • 在c++中处理对象

    有人告诉我 句柄是一种 空 指针 但 空指针 到底是什么意思以及它的目的是什么 另外 什么是 somehandle GetStdHandle STD INPUT HANDLE do 一般意义上的句柄是唯一标识对象的不透明值 在这种情况下 不
  • 从代码隐藏更改 IFrames InnerHtml

    我正在尝试在运行时从后面的代码设置 Iframe 的 HTML 在我的 aspx 页面中 我有
  • 从 React Native 中删除 Expo

    我在使用这个工具时遇到了很多麻烦 我认真地调试了expo 而不是应用程序本身 如何从 CRNA 中完全删除 expo 我想使用 CRNA 及其调试工具而不需要博览会 您可以通过弹出正在运行的应用程序来完成此操作npm 运行弹出 然后 如果您
  • 为什么我不能执行 操作?

    如果 html 文件在本地 在我的 C 驱动器上 则它可以工作 但如果 html 文件在服务器上并且图像文件在本地 则不行 这是为什么 有什么可能的解决方法吗 如果客户端可以请求本地文件系统文件 然后使用 JavaScript 找出其中的内
  • 如何更改Eclipse默认工作区?

    在哪里可以更改 Eclipse 中的默认工作区 如果您的意思是 更改工作空间 请转到File gt Switch Workspace
  • 为什么 bean 验证最小/最大约束不支持 double 类型?

    有人可以向我解释一下为什么 JPA 支持doubletype 作为字段类型 但 bean 验证约束javax validation constraints i e Min http java sun com javaee 6 docs ap
  • Flow 不允许我将 `Array` 传递给 `Array`(子类型数组到超类型数组)

    我有一个类型的值Array a 子类型数组 Flow 不允许我将其传递到期望的地方Array a 一组超类型 尽管它显然有效 例如 我无法用 type 赋值Array lt left right gt 到一个类型为的变量Array a a