用强数据类型保护你的表单数据-基于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 >
🎉🎊 恭喜,现在你的表单已经被类型完整的保护了。
作者:京东零售 王凡
来源:京东有开发者社区 转载请注明来源

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
记一次线上问题引发的对 Mysql 锁机制分析 | 京东物流技术团队
背景 最近双十一开门红期间组内出现了一次因 Mysql 死锁导致的线上问题,当时从监控可以看到数据库活跃连接数飙升,导致应用层数据库连接池被打满,后续所有请求都因获取不到连接而失败 整体业务代码精简逻辑如下: @Transaction public void service(Integer id) { delete(id); insert(id); } 数据库实例监控: 当时通过分析上游问题流量限流解决后,后续找时间又重新分析了下问题发生的根本原因,现将其总结如下:本篇文章会先对 Mysql 中的各种锁进行分析,包括互斥锁、间隙锁和插入意向锁,让大家对各种锁的使用场景有一个了解,然后在此基础上再对本问题进行分析,希望大家未来再碰到相似场景时,能够快速的定位问题 Mysql 锁机制 在 Mysql 中为了解决对同一行记录并发写的问题,引入了行锁机制,多个事务不能同时对一行数据进行修改操作,当需要对数据库中的一行数据进行修改时,会首先判断该行数据是否加锁,如果没加锁,那么当前事务加锁成功,可以进行后续的修改操作;但如果该行数据已经被其他事务加锁,则当前事务只有等待加锁的事务释放锁后才能加锁...
- 下一篇
飞码LowCode前端技术系列:如何便捷快速验证实现投产及飞码探索 | 京东云技术团队
本篇文章从数据中心,事件中心如何协议工作、不依赖环境对vue2.x、vue3.x都可以支持、投产页面问题定位三个方面进行分析。 一、数据中心,事件中心设计 飞码是数据驱动+事件驱动的产品,考虑到飞码运行环境,飞码自己封装了store。 数据中心:在同一个页面中可能存在多个飞码标签,飞码通过实例化实现store。在接入飞码的时候详见图1 图1 在运行的时候,飞码会对该部分创建一个实例。详见图2 图2 数据中心会根据当前运行环境,借用不同技术栈底层能力,实现数据流转。图2中JSONSchema来自图1中paasDSL或者通过页面id获取,其中页面pageId优先级最高。 事件中心:页面生命周期函数与用户操作的时候会触发事件,事件可能会触发其他事件。事件类型详见飞码[LowCode前端技术(三)]。飞码事件通过实例化对象实现,事件被触发的时候会创建一个事件实例eventCenter,编辑态事件产物eventId与事件中心相对应。有时会弹框消失的时候会触发其他事件,其它事件持续执行任务。飞码引入事件增强机制,对弹框消失的时候进行监控,并持续执行之前任务。详见图3 图3 事件中心会触发数据...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Linux系统CentOS6、CentOS7手动修改IP地址
- 2048小游戏-低调大师作品
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- CentOS8编译安装MySQL8.0.19
- CentOS6,CentOS7官方镜像安装Oracle11G
- CentOS7,8上快速安装Gitea,搭建Git服务器
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- MySQL8.0.19开启GTID主从同步CentOS8
- SpringBoot2更换Tomcat为Jetty,小型站点的福音