在迭代HTMLFormElement元素时纠正Flow类型?

时间:2017-06-08 15:15:57

标签: javascript flowtype

我有一个函数,它将一个表单元素作为输入,过滤其子元素(删除那些没有可序列化值的元素),然后返回一个{name: value}形式的对象。

类型检查似乎失败了,因为Flow告诉我传递给过滤器函数的每个元素只是一个基本的HTMLElement。我通过检查element.typeelement.name等进行过滤,由于HTMLElement没有这些属性,因此出现错误。

这两个过滤函数使用一个union类型,其中包含我期望在那里(HTMLInputElementHTMLTextAreaElement等)的相关元素来进行类型检查。靠自己这些工作。只有在过滤器中调用它们才会出现错误。

该模块的完整代码是:

/* @flow
 * Returns form data as a javascript object. Requires each
 * form element to have a name that corresponds to its value.
 */
type FormChild =
  | HTMLInputElement
  | HTMLSelectElement
  | HTMLTextAreaElement
  | HTMLButtonElement
  | HTMLFieldSetElement;

const isValidTarget = (el: FormChild): boolean => {
  return !(el instanceof HTMLFieldSetElement) &&
         !(el instanceof HTMLButtonElement) &&
         el.name !== '';
};

const isSerializable = (el: FormChild): boolean => {
  return (el.type === 'radio' && el.checked === true) ||
         (el.type === 'checkbox' && el.checked === true) ||
         (el.type !== 'radio' && el.type !== 'checkbox');
};


export default (form: HTMLFormElement): { [elementName: string]: string } => {
  return [...form.elements].filter((el) => isValidTarget(el) && isSerializable(el))
                           .reduce((data, el) => ({ [el.name]: el.value, ...data }), {});
};

我得到的错误都是指过滤器中的调用:

HTMLElement This type is incompatible with union: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement | HTMLButtonElement | HTMLFieldSetElement

reduce

有关

property 'name' Property not found in HTMLElement

property 'value' Property not found in HTMLElement

1 个答案:

答案 0 :(得分:1)

有两个步骤:

  • HTMLElementFormChild的投射类型,
  • HTMLFieldSetElement类型中移除FormChild,因为它不具有value属性,并将使用isValidTarget()进行过滤。
/* @flow
 * Returns form data as a javascript object. Requires each
 * form element to have a name that corresponds to its value.
 */
type FormChild =
  | HTMLInputElement
  | HTMLSelectElement
  | HTMLTextAreaElement;
//| HTMLButtonElement         <— removed, will be filtered by isValidTarget()
//| HTMLFieldSetElement;      <— removed, will be filtered by isValidTarget()

    const isValidTarget = (el: FormChild): boolean => {
      return !(el instanceof HTMLFieldSetElement) &&
             !(el instanceof HTMLButtonElement) &&
             el.name !== '';
    };

    const isSerializable = (el: FormChild): boolean => {
      return (el.type === 'radio' && el.checked === true) ||
             (el.type === 'checkbox' && el.checked === true) ||
             (el.type !== 'radio' && el.type !== 'checkbox');
    };


    export default (form: HTMLFormElement): { [elementName: string]: string } => {
//                                     `el: any` — prepare to cast
      return [...form.elements].filter((el: any) => isValidTarget(el) && isSerializable(el))
                               .reduce((data, el: FormChild) => ({ [el.name]: el.value, ...data }), {});
//                                           `el: FormChild` — type was casted
    };

使用流程测试:4.0.5