首页 > 解决方案 > 在 Flow 中打开联合类型

问题描述

此代码使用field.typewhich 是一个字符串来确定要呈现的组件。

SelectOptionsOverlay组件将呈现CardFormSelectField( type=="select") 及其options.

CardFormTextAreaOverlay将呈现CardFormTextAreaField( type=="textarea"),并且此组件将永远不会尝试使用options或任何其他不存在于CardFormTextAreaField.


export type CardFormSelectField = {
  title: string,
  type: string,
  placeholder: string,
  options: string[]
};

export type CardFormTextAreaField = {
  title: string,
  type: string
};

export type CardFormField = CardFormSelectField | CardFormTextAreaField;

overlay(field: CardFormField): ?(SelectOptionsOverlay | CardFormTextAreaOverlay) {
    const props = {...};
    switch (field.type) {
      case "select":
        return <SelectOptionsOverlay {...props} />;
      case "textarea":
        return <CardFormTextAreaOverlay {...props} />;
    }
  }

switch声明保证了这一切的安全。但是,Flow 并不“知道” switch 语句及其安全优势,因此它抱怨:

Cannot return <SelectOptionsOverlay /> because: 
Either React.Element [1] is incompatible with SelectOptionsOverlay [2].
Or React.Element [1] is incompatible with CardFormTextAreaOverlay [2].  

[1]是返回语句,[2]是函数返回值的类型声明:?(SelectOptionsOverlay | CardFormTextAreaOverlay)

CardFormTextAreaOverlay第二个 return 语句(for )也有相应的错误。

我实际上很难理解这意味着什么,更不用说是否可以修复它了。

另一方面,我理解得更好,如果我删除 return 语句的类型注释,Flow 只会抱怨 return 语句SelectOptionsOverlay,抱怨fieldprop 可能包含的内容options以及placeholder不存在于CardFormTextAreaField.

确实如此,但 switch 语句应该保护我们在实际返回时不会出现错误的道具。但是你不能打开 FlowType 可以吗?因为 Flow 不是真正的 JS?

标签: react-nativeflowtype

解决方案


如果可能并且对您的代码有意义,您可以专门type为每个CardFormField. 例如,代替type: stringfor CardFormSelectField,您可以拥有type: "select". 这样,Flow 就知道当它进入case "select"块时,它props的类型必须是CardFormSelectField. 目前,Flow 无法将每个case语句与联合类型中的特定类型相关联。

import React from 'react';

type CardFormSelectField = {|
  title: string,
  type: "select", // NEW!
  placeholder: string,
  options: string[]
|};

type CardFormTextAreaField = {|
  title: string,
  type: "textarea", // NEW!
|};

type CardFormField = CardFormSelectField | CardFormTextAreaField;

function SelectOptionsOverlay(props: CardFormSelectField) {
  return "SelectOptionsOverlay";
}

function CardFormTextAreaOverlay(props: CardFormTextAreaField) {
  return "CardFormTextAreaOverlay";
}

function Overlay(props: CardFormField) {
  switch (props.type) {
    case "select":
      (props: CardFormSelectField);
      return <SelectOptionsOverlay {...props} />;
    case "textarea":
      (props: CardFormTextAreaField);
      return <CardFormTextAreaOverlay {...props} />;
  }
}

尝试流


推荐阅读