概述

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

我在之前的作业中常常为了方便,直接将接口数据类型复用为表单内数据类型,在遇到特点类型不一致的状况时会使用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 >

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

作者:京东零售 王凡

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