在迭代Object.entries时,Flow似乎假设错误的类型

时间:2017-09-29 15:49:48

标签: javascript reactjs flowtype

编辑:因为这似乎是一个错误,我在Github上发布了一个问题#4997

在下面的示例中,Flow似乎假设label的类型为mixed,即使Props声明和匿名函数声明都将其绑定到Node。我错过了什么?

/* @flow */
import React from 'react';
import type { Node } from 'react';

type Props = {
  values: { [string]: Node },
  /* … */
};

export default class SelectButtons extends React.Component<Props> {
  /* … */

    createButtons(): Array<Node> {
    return Object.entries(this.props.values).map(
      ([value: string, label: Node], index: number): Node => (
        <button>
          {label}
        </button>
      ),
    );
  }
}

这是错误消息:

             v------
 44:         <button
 45:           onClick={() => this.choose(value)}
 46:           key={index}
 47:           className={this.block('option', { selected: value === this.state.value })()}
 48:         >
             ^ React element `button`
             v------
 44:         <button
 45:           onClick={() => this.choose(value)}
 46:           key={index}
 47:           className={this.block('option', { selected: value === this.state.value })()}
 48:         >
             ^ React element `button`. This type is incompatible with
                v
170:     props: {
171:       children?: React$Node,
172:       [key: string]: any,
173:     },
         ^ object type. See lib: /tmp/flow/flowlib_3bead812/react-dom.js:170
  Property `children` is incompatible:
     49:           {label}
                    ^^^^^ mixed. This type is incompatible with
    171:       children?: React$Node,
                          ^^^^^^^^^^ union: undefined | null | boolean | number | string | type application of type `React$Element` | type application of identifier `Iterable`. See lib: /tmp/flow/flowlib_3bead812/react-dom.js:171
      Member 1:
       15:   | void
               ^^^^ undefined. See lib: /tmp/flow/flowlib_3bead812/react.js:15
      Error:
       49:           {label}
                      ^^^^^ mixed. This type is incompatible with
       15:   | void
               ^^^^ undefined. See lib: /tmp/flow/flowlib_3bead812/react.js:15
      Member 2:
       16:   | null
               ^^^^ null. See lib: /tmp/flow/flowlib_3bead812/react.js:16
      Error:
       49:           {label}
                      ^^^^^ mixed. This type is incompatible with
       16:   | null
               ^^^^ null. See lib: /tmp/flow/flowlib_3bead812/react.js:16
      Member 3:
       17:   | boolean
               ^^^^^^^ boolean. See lib: /tmp/flow/flowlib_3bead812/react.js:17
      Error:
       49:           {label}
                      ^^^^^ mixed. This type is incompatible with
       17:   | boolean
               ^^^^^^^ boolean. See lib: /tmp/flow/flowlib_3bead812/react.js:17
      Member 4:
       18:   | number
               ^^^^^^ number. See lib: /tmp/flow/flowlib_3bead812/react.js:18
      Error:
       49:           {label}
                      ^^^^^ mixed. This type is incompatible with
       18:   | number
               ^^^^^^ number. See lib: /tmp/flow/flowlib_3bead812/react.js:18
      Member 5:
       19:   | string
               ^^^^^^ string. See lib: /tmp/flow/flowlib_3bead812/react.js:19
      Error:
       49:           {label}
                      ^^^^^ mixed. This type is incompatible with
       19:   | string
               ^^^^^^ string. See lib: /tmp/flow/flowlib_3bead812/react.js:19
      Member 6:
       20:   | React$Element<any>
               ^^^^^^^^^^^^^^^^^^ type application of type `React$Element`. See lib: /tmp/flow/flowlib_3bead812/react.js:20
      Error:
       49:           {label}
                      ^^^^^ mixed. Inexact type is incompatible with exact type
       20:   | React$Element<any>
               ^^^^^^^^^^^^^^^^^^ exact type: object type. See lib: /tmp/flow/flowlib_3bead812/react.js:20
      Member 7:
       21:   | Iterable<React$Node>;
               ^^^^^^^^^^^^^^^^^^^^ type application of identifier `Iterable`. See lib: /tmp/flow/flowlib_3bead812/react.js:21
      Error:
       49:           {label}
                      ^^^^^ mixed. This type is incompatible with
       21:   | Iterable<React$Node>;
               ^^^^^^^^^^^^^^^^^^^^ $Iterable. See lib: /tmp/flow/flowlib_3bead812/react.js:21
        Property `@@iterator` is incompatible:
           21:   | Iterable<React$Node>;
                   ^^^^^^^^^^^^^^^^^^^^ property `@@iterator` of $Iterable. Property not found in. See lib: /tmp/flow/flowlib_3bead812/react.js:21
           49:           {label}
                          ^^^^^ mixed

1 个答案:

答案 0 :(得分:1)

现在,我假设这是一个错误。如果您认为我错了,并且有更好的答案,请随时回答,我会很乐意接受!

我认为这是一个错误,因为以下解决方法:

createButtons(): Array<Node> {
  return Object.keys(this.props.values).map((value: string, index: number): Node => (
    <button>
      {this.props.values[value]}
    </button>
  ));
}

通过直接引用对象,而不是使用Object.entries对其进行迭代,现在流程采用正确的类型。

编辑:正如我已经多想一想,问题在于数组的类型化,以及Flow中的数组只能为其元素提供一种类型的事实。

Object.entries()的回调参数属于Array<mixed> => void类型。理想的类型是Array<[K, V]> => void,其中KV分别是对象的键和值类型(K总是string,I想。)

这将需要异构集合,其中Array<[K, V]>由所有长度为2的数组居住,其第一个元素的类型为K,第二个类型为V。这可能需要Flow(目前)无法提供的某些类型级别的运算符和更高级的类型。

使用Object.keys的解决方法有效,因为Object.keys不需要异构数组(所有键都属于同一类型)但如果对象看起来不像{ [string]: X },它可能会失败但是,它具有不同类型的值(比如{ foo: number, bar: string },使它(再次)成为异构集合。