写点什么

用强数据类型保护你的表单数据 - 基于 antd 表单的类型约束 | 京东云技术团队

  • 2023-11-15
    北京
  • 本文字数:1409 字

    阅读完需:约 5 分钟

用强数据类型保护你的表单数据-基于antd表单的类型约束 | 京东云技术团队

概述

接口数据类型与表单提交数据类型,在大多数情况下,大部分属性的类型是相同的,但很少能做到完全统一。


我在之前的工作中经常为了方便,直接将接口数据类型复用为表单内数据类型,在遇到属性类型不一致的情况时会使用any强制忽略类型错误。


后来经过自省与思考,这种工作模式会引起各种隐藏 bug,一定有更好的工程解决方案。


我的答案就是:为表单提交数据单独定义类型!

类型解说

接口定义的请求体类型

请求数据类型


type RequestBody = {   name?: string   count?: number   groupIds?: number[]   startDate?: string // YYYY-MM-DD}
复制代码

表单提交数据类型定义

type FormValue = {  name?: string  count?: number  groupIds?: string  startDate?: Moment}
复制代码


有了该类型,我们可以方便的将该类型使用在表单实例上


const [form] = Form.useForm< FormValue >()
复制代码

类型复用优化

如果表单的数据类型和接口提交的数据类型完全一致,当然可以共用一个,但现实世界这种情况几乎没有。


大多数情况是可以复用一些接口的属性到表单的数据类型中,例如上面的两个数据结构,其中 name、id 属性是相同的,则 FormValue 可以优化为


type FormValue = Pick< RequestBody, 'name' | 'count' > {  groupIds?: string  startDate?: Moment}
复制代码

Form.Item 限定 name 优化

应用此时表单组件的name约束就应为我们自定义的表单数据类型FormValue,定义约束组件


const FormItem = Form.Item as React.FC<  Omit< FormItemProps, 'name' > & {    name: keyof FormValue  }>
复制代码


应用该约束组件


< FormItem label="名称" name="name" > ...
复制代码

数据转换

在表单的onFinish提交过程中,需要一个将**FormValue(表单数据)转换为 RequestBody(提交数据)**的函数,类型定义如下:


const formValueToRquestBody = (values: FormValue): RequestBody => {  return {    name: values.name,    id: values.id,    groupIds: values.groupIds.split(',').map(n => Number(n)),    startDate: values.startDate?.format('YYYY-MM-DD'),  }}
复制代码

复杂表单类型

复杂表单有些表单数据并非一层的key => value,而是多层树状或数组结构。


例如:提交数据结构


type FormValue = {  name: string  rule: {    min: number    max: number  }}
复制代码


表单中关于 rule 的写法为:


< Form.Item name={['rule', 'min']}>
复制代码


这种情况下,name不再是简单的字符串,应该如何用类型约束?


如果可以我希望使用类型工具,兼容多层表单数据结构,但一直没成功。


我目前的方法是,为该表单层级安排一个专用类型,该方法会有些写的麻烦,但胜在能准确的定义好类型。


我在采用该方法校验表单 name 数据时发现了几个很难发现的拼写错误,提前制止了测试同学提 bug 过来。


例如为rule属性定义单独的RuleFormItem


import type { FormItemProps } from 'antd'
const RuleFormItem = Form.Item as React.FC< Omit< FormItemProps, 'name'> & { name: ['rule', keyof FormValue['rule']] }>
复制代码


调用时


< RuleFormItem label="min" name={['rule', 'min']}> ...
复制代码


此时数组中的 rule 与 min 都能收到类型的保护。

泛型抽象

export type TypedFormItem< T > = React.FC<  Omit< FormItemProps, 'name' > & {    name: T  }>
复制代码

应用泛型

const RuleFormItem = Form.Item as TypedFormItem< keyof FormValue >
复制代码


🎉🎊 恭喜,现在你的表单已经被类型完整的保护了。


作者:京东零售 王凡

来源:京东有开发者社区 转载请注明来源

发布于: 刚刚阅读数: 5
用户头像

拥抱技术,与开发者携手创造未来! 2018-11-20 加入

我们将持续为人工智能、大数据、云计算、物联网等相关领域的开发者,提供技术干货、行业技术内容、技术落地实践等文章内容。京东云开发者社区官方网站【https://developer.jdcloud.com/】,欢迎大家来玩

评论

发布
暂无评论
用强数据类型保护你的表单数据-基于antd表单的类型约束 | 京东云技术团队_数据类型_京东科技开发者_InfoQ写作社区