1.代码
interface FData {
[k: string]: string | number | null | undefined | FData
}
type Rule<T> = {
key: keyof T
message: string
} & (
{ type: 'required' } |
{ type: 'pattern', regex: RegExp }
)
type Rules<T> = Rule<T>[]
export type { Rules, Rule, FData }
export const validate = <T extends FData>(formData: T, rules: Rules<T>) => {
type Errors = {
[k in keyof T]?: string[]
}
const errors: Errors = {}
rules.map(rule => {
const { key, type, message } = rule
const value = formData[key]
switch (type) {
case 'required':
if (isEmpty(value)) {
errors[key] = errors[key] ?? []
errors[key]?.push(message)
}
break;
case 'pattern':
if (!isEmpty(value) && !rule.regex.test(value!.toString())) {
errors[key] = errors[key] ?? []
errors[key]?.push(message)
}
break;
default:
return
}
})
return errors
}
function isEmpty(value: null | undefined | string | number | FData) {
return value === null || value === undefined || value === ''
}
2.使用
const formData = reactive({
name: "",
sign: "",
});
const errors = reactive<{ [k in keyof typeof formData]?: string[] }>({ });
const onSubmit = (e: Event) => {
const rules: Rules<typeof formData> = [
{ key: "name", type: "required", message: "必填" },
{
key: "name",
type: "pattern",
regex: /^.{1,4}$/,
message: "只能填 1 到 4 个字符",
},
{ key: "sign", type: "required", message: "必填" },
];
Object.assign(errors, {
name: undefined,
sign: undefined,
});
Object.assign(errors, validate(formData, rules));
e.preventDefault();
};
return () => (
<form class={s.form} onSubmit={onSubmit}>
)