我有一个函数,它将一个表单元素作为输入,过滤其子元素(删除那些没有可序列化值的元素),然后返回一个{name: value}
形式的对象。
类型检查似乎失败了,因为Flow告诉我传递给过滤器函数的每个元素只是一个基本的HTMLElement
。我通过检查element.type
,element.name
等进行过滤,由于HTMLElement
没有这些属性,因此出现错误。
这两个过滤函数使用一个union类型,其中包含我期望在那里(HTMLInputElement
,HTMLTextAreaElement
等)的相关元素来进行类型检查。靠自己这些工作。只有在过滤器中调用它们才会出现错误。
该模块的完整代码是:
/* @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
答案 0 :(得分:1)
有两个步骤:
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