鸿蒙 ArkTS 表单数据怎么处理?用 @hmkit/validator 做类型转换和嵌套校验
开发鸿蒙应用时,表单里显示的是“数量”,拿到的却常常是字符串;接口返回的布尔值,有时又是 "false"。
如果直接转换,可能碰到这些结果:
Number(''); // 0
Boolean('false'); // true
转换成功,并不代表符合业务预期。订单里没有填写数量,不能因为转换后得到 0,就当作已经填写;接口返回 "false",也不应该被当作 true。
我维护的开源库 @hmkit/validator,除了手机号、身份证等字段规则,也支持数据预处理、类型转换、对象与数组校验,以及按字段路径返回错误。
这篇以一个订单录入场景为例,演示如何把原始输入处理成业务需要的数据。示例使用已在 OHPM 上架的 1.4.0,文中的转换与嵌套校验能力在此前版本中已经提供。
1. 安装与最小示例
在项目使用的模块目录中执行:
ohpm install @hmkit/validator@1.4.0
先校验一个手机号:
import { v } from '@hmkit/validator';
const phoneRule = v.string()
.required('请输入手机号')
.phone('手机号格式不正确');
const checked = phoneRule.validate('123');
console.info(JSON.stringify(checked));
结果包含 valid 和 errors,不需要为正常的校验失败编写 try/catch。
对于简单输入,可以直接读取错误提示;字段变多后,则可以把规则组合成对象 Schema。
2. 类型转换要明确接受哪些输入
库提供了 coerceNumber()、coerceBoolean() 等转换入口,通过 parse() 获取结果:
import { v } from '@hmkit/validator';
const count = v.coerceNumber().parse('12');
console.info(JSON.stringify(count));
// { "success": true, "value": 12, "errors": [] }
const enabled = v.coerceBoolean().parse('false');
console.info(JSON.stringify(enabled));
// { "success": true, "value": false, "errors": [] }
几种常见输入的行为如下:
| 规则 | 输入 | 结果 |
|---|---|---|
coerceNumber() | ' 12.5 ' | 成功,得到数字 12.5 |
coerceNumber() | '' | 失败 |
coerceNumber() | true | 失败 |
coerceNumber() | 'Infinity' | 失败 |
coerceBoolean() | 'false' | 成功,得到 false |
coerceBoolean() | 1 / 0 | 成功,分别得到 true / false |
coerceBoolean() | 'yes' | 失败 |
这些入口适合协议明确的基础类型转换。它们不自动表示“必填”或“必须大于 0”;null、undefined 等空值仍受内部规则的空值语义影响。
如果需要同时约束必填、整数和范围,可以用下一节的 preprocess():先处理输入,再交给数字规则校验。
3. 把数量转换和业务约束放在一起
假设订单数量必须是 1~99 的整数,输入可能来自 TextInput,因此先处理字符串:
import { v } from '@hmkit/validator';
const quantitySchema = v.preprocess<number>(
(value: Object | null | undefined): Object | null | undefined => {
if (typeof value !== 'string') {
return value;
}
const text = value.trim();
return text === '' ? undefined : Number(text);
},
v.number()
.required('请输入数量')
.integer('数量必须为整数')
.min(1, '数量至少为 1')
.max(99, '数量不能超过 99')
);
处理顺序是:
- 字符串先去除两侧空格。
- 空白输入转为缺失值,由
required()返回必填提示。 - 其余字符串尝试转为数字。
- 数字继续经过整数和范围校验。
因此,'2' 得到数字 2,空白输入、'abc'、'1.5'、'0' 都无法通过这套完整规则。
这里的数量转换使用 Number()。如果接口只允许特定的十进制文本格式,可以在预处理函数中增加格式约束;金额计算和超大整数也应按业务精度要求单独设计。
4. 对象和数组可以继续组合
现在把数量规则放进订单。下面的代码接在上一节之后:
interface OrderItem {
sku: string;
quantity: number;
}
interface OrderData {
phone: string;
items: Array<OrderItem>;
}
const orderSchema = v.object<OrderData>({
'phone': v.string()
.required('请输入手机号')
.phone('手机号格式不正确'),
'items': v.array<OrderItem>(
v.object<OrderItem>({
'sku': v.string().required('请选择商品'),
'quantity': quantitySchema
}).strip()
)
.required('请添加商品')
.nonEmpty('至少添加一件商品')
}).strip();
const rawInput: Record<string, Object> = {
'phone': '13800138000',
'items': [
{ 'sku': 'SKU-001', 'quantity': '2', 'selected': true }
],
'previewMode': true
};
const parsed = orderSchema.parse(rawInput);
if (parsed.success && parsed.value !== undefined) {
const order: OrderData = parsed.value;
console.info(JSON.stringify(order));
// 在这里把 order 交给提交请求等业务逻辑。
}
解析后的数据是:
{
"phone": "13800138000",
"items": [
{ "sku": "SKU-001", "quantity": 2 }
]
}
这个过程完成了三件事:校验手机号和商品结构,把数量从字符串转成数字,移除示例中的两个界面辅助字段。
其中,.strip() 只处理它所在的对象层级。因此订单对象和商品对象分别配置了 .strip()。
对象默认会保留未知字段。如果希望多出的字段直接报错,可以改用 .strict();如果希望接受这些字段,但不让它们进入解析结果,就使用 .strip()。
示例通过 v.object<OrderData>() 显式指定输出模型。业务接口和 Schema 的一致性仍需要开发者维护,泛型声明不会自动证明每个字段的规则都正确。
5. 出错时,定位到数组中的具体字段
商品列表中第二件商品的数量出错,只显示“表单填写有误”还不够,页面需要知道具体是哪一行。
@hmkit/validator 会把嵌套错误拼成字段路径:
import { flattenErrors } from '@hmkit/validator';
const invalidInput: Record<string, Object> = {
'phone': '13800138000',
'items': [
{ 'sku': 'SKU-001', 'quantity': '2' },
{ 'sku': 'SKU-002', 'quantity': '0' }
]
};
const failed = orderSchema.parse(invalidInput);
if (!failed.success) {
const fieldErrors = flattenErrors(failed.errors);
console.info(JSON.stringify(fieldErrors));
}
输出为:
{
"items.1.quantity": ["数量至少为 1"]
}
items.1.quantity 表示商品数组中下标为 1,也就是第二件商品的数量字段。
业务层可以把这个路径映射到对应行的错误提示。原始错误还包含 message,内置规则提供的 code 可用于分类处理;flattenErrors() 则把同一路径的提示整理为数组,方便界面读取。
6. validate 和 parse 应该怎么选
| 需求 | 使用入口 | 读取内容 |
|---|---|---|
| 判断输入是否通过 | validate() | valid、errors |
| 获取转换、默认值或字段过滤后的数据 | parse() | success、value、errors |
| 规则包含远程异步校验 | validateAsync() / parseAsync() | 对应的异步结果 |
本文包含数量转换和未知字段过滤,所以提交时应使用成功解析后的 value。
如果只检查结果是否通过,随后仍提交 rawInput,数量依旧是字符串,界面辅助字段也仍然存在。校验结果和业务实际使用的数据,需要在这里接起来。
7. 这个库还适合哪些场景
除了本文的订单录入,它还可以用于注册资料、实名认证信息录入、企业资料表单和接口数据检查:
- 中国本地化字段规则:手机号、身份证、银行卡、车牌、统一社会信用代码等,减少项目中重复维护校验逻辑的工作。格式和校验位检查仍需与业务侧的身份核验区分开。
- ArkUI 表单联动:
FormValidator提供输入、失焦、提交等触发方式,以及字段错误和校验状态,适合需要交互反馈的页面。 - 规则复用:对象 Schema 支持
partial()、pick()、omit();需要为不同场景构建独立可变规则时,1.4.0 还提供可选的SchemaFactory入口。
可以先挑一个表单接入,把字段规则、错误展示和提交数据串起来,再根据项目需要逐步使用其他能力。
开源地址与使用文档
@hmkit/validator 使用 MIT 开源协议。源码、示例和使用说明都在仓库中:
我会继续维护这个库。欢迎在自己的鸿蒙项目中试用,也欢迎带着具体的输入、预期结果和复现代码提 Issue,让后续改进更贴近实际使用场景。
更多推荐


所有评论(0)