【问题标题】:Flow doesn’t let me pass `Array<A>` to `Array<A | B>` (array of subtypes to array of supertypes)Flow 不允许我将 `Array<A>` 传递给 `Array<A | B>`(子类型数组到超类型数组)
【发布时间】:2018-08-30 07:11:30
【问题描述】:

我有一个Array&lt;A&gt; 类型的值(子类型数组)。 Flow 不允许我将它传递到需要 Array&lt;A | B&gt;(超类型数组)的地方,尽管它显然有效。

例如,我不能将类型为 Array&lt;'left' | 'right'&gt; 的值分配给类型为 Array&lt;string&gt; 的变量:

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

同样,我不能将Array&lt;ANode&gt; 传递给采用Array&lt;Node&gt; 的函数,即使NodeANode | 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

【问题讨论】:

  • 这个问题和Flow Array type fails on subset of that type的问题差不多。我发布了这个问题,而不是在该问题上添加新答案,原因有两个:为人们提供更好、简化的示例以了解问题,并为搜索此问题的人们提及不同的关键字。这两个原因中的第一个可能表明这个问题不应该作为重复关闭。

标签: javascript arrays flowtype


【解决方案1】:

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

运行上述代码后,nodesSubtype 将包含 BNode,即使它被声明为 ANode 的数组,违反了它的类型。

有两种解决方案可以让 Flow 相信您不会改变数组。最明确的方法是Array 替换为 Flow 实用程序类型$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

您只需在函数参数的类型中进行替换(例如nodes),但如果您愿意,可以在任何适用的地方使用$ReadOnlyArray(例如nodesSubtype)。

$ReadOnlyArray 是最安全的解决方案,但您可能不想更改所有现有函数来使用它。在这种情况下,您的替代方法是通过any 转换数组类型。是的,你可以从一开始就这样做,但至少现在你知道为什么这样做是安全的。您甚至可以发表评论解释为什么存在这种演员表,这可能有助于您发现假设不再有效。

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

如果你不关心记录问题,你可以省略评论,只投到any

getFirstNodeType((nodesSubtype: any));

Try Flow demo

其他资源

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-25
    • 1970-01-01
    • 2013-01-31
    • 1970-01-01
    • 2017-04-03
    • 1970-01-01
    • 1970-01-01
    • 2011-06-18
    相关资源
    最近更新 更多