Правильные типы потока при переборе элементов HTMLFormElement?

1

У меня есть функция, которая принимает элемент формы как входной, фильтрует его дочерние элементы (удаляя их без сериализуемых значений), а затем возвращает объект формы {name: value}.

Ошибка typechecking, кажется, терпит неудачу, потому что Flow сообщает мне, что каждый элемент, переданный функции фильтра, является всего лишь базовым HTMLElement. Я фильтрую, проверяя element.type, element.name т.д., А поскольку HTMLElement не имеет этих свойств, возникает ошибка.

Две функции фильтрации используют тип объединения, содержащий соответствующие элементы, которые я ожидаю там (HTMLInputElement, HTMLTextAreaElement т.д.) Для typecheck. Само по себе эти работы. Только когда они вызываются в фильтр, я получаю ошибки.

Полный код для модуля:

/* @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

Теги:
flowtype

1 ответ

1
Лучший ответ

Есть два шага:

  • cast type из HTMLElement в FormChild,
  • удалите 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

  • 1
    Спасибо! Поскольку входными данными для функций фильтра мог быть любой дочерний элемент формы, я предполагал, что мне нужно включить те дочерние элементы, которые будут отфильтрованы. Ваше решение имеет большой смысл.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню