流程:在另一种道具的基础上优化一种道具的价值

时间:2018-08-09 18:37:47

标签: javascript types flowtype

我有一个自动完成功能,可以根据是否将prop multiple传递给它来保存一个值或多个值。如果它是多个,那么它所保存的值将至少是一个空数组-永远不会为null。如果是单值自动完成,则该值确实可以为null。我正在努力正确地键入此类型,以便传递给它的onBlur函数根据multiple道具是否已传递给自动完成功能而知道期望使用哪种值类型。

Here's a link to the live flow.org testing page。我得到的错误出现在以下代码示例末尾的两行onBlur={...}中。错误是:

39:   | { multiple: true, onBlur: ValueT[] => void }
                                  ^ array type [1] is incompatible with null or undefined [2].
References:
39:   | { multiple: true, onBlur: ValueT[] => void }
                                  ^ [1]
38:   | { multiple: false, onBlur: ?ValueT => void }
                                   ^ [2]
39:   | { multiple: true, onBlur: ValueT[] => void }
                                  ^ array type [1] is incompatible with `ValueT` [2].
References:
39:   | { multiple: true, onBlur: ValueT[] => void }
                                  ^ [1]
38:   | { multiple: false, onBlur: ?ValueT => void }
                                    ^ [2]
41: const AutocompleteWrapper = ({ multiple, onBlur }: AutocompleteWrapperT) => (
                                   ^ boolean literal `true` [1] is incompatible with boolean literal `false` [2].
References:
39:   | { multiple: true, onBlur: ValueT[] => void }
                    ^ [1]
38:   | { multiple: false, onBlur: ?ValueT => void }
                    ^ [2]
43:     ? <AutocompleteMulti onBlur={onBlur} />
                                    ^ Cannot create `AutocompleteMulti` element because `ValueT` [1] is incompatible with array type [2] in the first argument of property `onBlur`.
References:
38:   | { multiple: false, onBlur: ?ValueT => void }
                                    ^ [1]
20: type AutocompleteMultiPropsT = { onBlur: ValueT[] => void }
                                             ^ [2]
type ValueT = { id: number }
type SyntheticInputEventT = { target: { value: ?ValueT } }

type AutocompleteSinglePropsT = { onBlur: ?ValueT => void }

class AutocompleteSingle extends React.Component<AutocompleteSinglePropsT> {

  onBlur = (e: SyntheticInputEventT) => {
    this.props.onBlur(e.target.value || null)
  }

  render(): React.Node {
    return <input onBlur={this.onBlur} />
  }
}

type AutocompleteMultiPropsT = { onBlur: ValueT[] => void }
type AutocompleteMultiStateT = { value: ValueT[] }

class AutocompleteMulti extends React.Component<AutocompleteMultiPropsT, AutocompleteMultiStateT> {
  values: ValueT[]

  onBlur = (e: SyntheticInputEventT) => {
    if (!e.target.value) return
    this.values = [...this.values, e.target.value]
    this.props.onBlur(this.values)
  }

  render(): React.Node {
    return <input onBlur={this.onBlur} />
  }
}

type AutocompleteWrapperT = 
  | { multiple: false, onBlur: ?ValueT => void }
  | { multiple: true, onBlur: ValueT[] => void }

const AutocompleteWrapper = ({ multiple, onBlur }: AutocompleteWrapperT) => (
  multiple
    ? <AutocompleteMulti onBlur={onBlur} />
    : <AutocompleteSingle onBlur={onBlur} />
)

const CmpWithSingle = () => (
   <AutocompleteWrapper onBlur={v => console.log(v ? v.id : null)} multiple={false} />
)

const CmpWithMulti = () => (
   <AutocompleteWrapper onBlur={v => console.log(v.length)} multiple />
)

我也尝试过使用type="single"/"multiple"而不是布尔multiple道具,但这没有影响。我还尝试了以下替代方法来定义AutocompleteWrapperT联合类型,但这会产生一些额外的流错误:

type BaseAutocompleteWrapperT<V, M: boolean> = {
  multiple?: M,
  onBlur: V => void
};

type AutocompleteWrapperT =
  | BaseAutocompleteWrapperT<?ValueT, false>
  | BaseAutocompleteWrapperT<ValueT[], true>

1 个答案:

答案 0 :(得分:0)

Flow有一个unfortunate destructuring bug,在其中它不维护多个解构结果之间的关系。您可以通过避免在此处进行破坏来解决此问题:

const AutocompleteWrapper = (props: AutocompleteWrapperT) => (
  props.multiple
    ? <AutocompleteMulti onBlur={props.onBlur} />
    : <AutocompleteSingle onBlur={props.onBlur} />

Working Flow Try