流类型和多态性

时间:2019-08-29 16:27:05

标签: reactjs react-native flowtype

下面的组件采用fields个对象的Field数组。 Field类由SelectboxField扩展(和其他字段,但这是到目前为止的代码)。组件确定字段的类型并呈现该字段的特定组件。特定的组件,例如SelectboxFieldView将特定类型的字段(SelectboxField)作为属性。

// @flow
import React, { Component } from "react";
import { Text, View } from "react-native";
import Field from "../models/fields/Field";
import SelectboxFieldView from "../components/SelectboxFieldView";
import SelectboxField from "../models/fields/SelectboxField";

type Props = { fields: Field[] };
type State = {};

class FieldsRenderer extends Component<Props, State> {
  render() {
    const MockFields = [
      this.props.fields.find(f => f.type === "selectbox") || new Field()
    ]; 

    // const fields = this.props.fields
    const fields = MockFields
    return (
      <View>
        {fields.map((field, i: number) => {
          switch (field.constructor) {
            case SelectboxField:
              const selField: SelectboxField = field;  // ERROR HERE
              return <SelectboxFieldView key={i} field={selField} />;
            default:
              return <Text key={i}>A Field</Text>;
          }
        })}
      </View>
    );
  }
}
export default FieldsRenderer;

我在指示的行上field上出现流错误,说:

Cannot assign field to selField because Field is incompatible with SelectField`

无论有没有selField的显式类型定义,都会出现此错误。

我也尝试过类型转换表达式:

 switch (field.constructor) {
            case SelectboxField:
              (field: SelectboxField);
              return <SelectboxFieldView key={i} field={field} />;

但是它说“无法将字段转换为SelectboxField,因为Field与SelectboxField不兼容

这似乎不正确:

// @flow

class Field {
  title: string;
  type: string;

  static fromApiFormInfo(formInfo: Object): Field {
    const field = new Field();
    field.title = formInfo.title;
    field.type = formInfo.type;
    return field;
  }
}

export default Field;
// @flow
import Field from "./Field";

class SelectboxField extends Field {
  placeholder: string;
  options: string[];

  static fromApiFormInfo(formInfo: Object): SelectboxField {
    const base = new SelectboxField();
    const baseField = super.fromApiFormInfo(formInfo);
    const field: SelectboxField = Object.assign(base, { ...baseField });
    field.options = formInfo.options;
    field.placeholder = formInfo.placeholder_text;
    return field;
  }
}

export default SelectboxField;

有没有办法解决这个问题?

1 个答案:

答案 0 :(得分:1)

switch (field.constructor) {
  case SelectboxField:
为了理解fieldSelectboxField

不是Flow可以作为type refinement处理的东西。你想做

if (field instanceof SelectboxField) {
  return <SelectboxFieldView key={i} field={field} />;
} else {
  return <Text key={i}>A Field</Text>;
}