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

概述

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

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

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

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

类型解说

接口定义的请求体类型

请求数据类型

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

表单提交数据类型定义

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

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

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

类型复用优化

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

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

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

Form.Item 限定 name 优化

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

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

应用该约束组件

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

数据转换

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

css 复制代码
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,而是多层树状或数组结构。

例如:提交数据结构

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

表单中关于rule 的写法为:

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

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

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

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

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

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

typescript 复制代码
import type { FormItemProps } from 'antd'

const RuleFormItem = Form.Item as React.FC<
  Omit< FormItemProps, 'name'> & {
    name: ['rule', keyof FormValue['rule']]
  }
>

调用时

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

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

泛型抽象

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

应用泛型

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

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

作者:京东零售 王凡

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

相关推荐
weixin_4277716114 分钟前
前端调试隐藏元素
前端
无忧智库1 小时前
跨行业数据要素可信流通体系建设:打破信任壁垒的完整工程方法论(WORD)
大数据·人工智能
小王毕业啦1 小时前
2007-2024年 省级-农林牧渔总产值、农业总产值数据(xlsx)
大数据·人工智能·数据挖掘·数据分析·社科数据·实证分析·经管数据
数据皮皮侠1 小时前
上市公司创新韧性数据(2000-2024)|顶刊同款 EIR 指数
大数据·人工智能·算法·智慧城市·制造
爱上好庆祝1 小时前
学习js的第五天
前端·css·学习·html·css3·js
科研前沿1 小时前
纯视觉无感解算 + 动态数字孪生:室内外无感定位技术全新升级
大数据·人工智能·算法·重构·空间计算
C澒1 小时前
IntelliPro 产研协作平台:基于 AI Agent 的低代码智能化配置方案设计与实现
前端·低代码·ai编程
一袋米扛几楼982 小时前
【Git】规范化协作:详解 GitHub 工作流中的 Issue、Branch 与 Pull Request 最佳实践
前端·git·github·issue
网络点点滴2 小时前
前端与后端的区别与联系
前端
科研前沿2 小时前
什么是时空融合技术?
大数据·人工智能·数码相机·算法·重构·空间计算