fix(components): [form] improve types (#12549)

* fix(components): [form] improve types

* fix(components): [form] improve FormRules type, support object and array

* fix(components): [form] improve FormRules type with comment

* fix(components): [form] allow number as key in FormRules type

* chore(components): [form] fix FormRules type example

* chore: remove extra import

* chore: update form/custom-validation and form/validation examples

* chore(components): [form] update example
This commit is contained in:
Wu Rui
2023-06-11 20:36:27 +08:00
committed by GitHub
parent 11c79f3003
commit 01f74e7536
3 changed files with 92 additions and 4 deletions

View File

@ -79,7 +79,7 @@ const ruleForm = reactive({
age: '',
})
const rules = reactive<FormRules>({
const rules = reactive<FormRules<typeof ruleForm>>({
pass: [{ validator: validatePass, trigger: 'blur' }],
checkPass: [{ validator: validatePass2, trigger: 'blur' }],
age: [{ validator: checkAge, trigger: 'blur' }],

View File

@ -83,9 +83,21 @@
import { reactive, ref } from 'vue'
import type { FormInstance, FormRules } from 'element-plus'
interface RuleForm {
name: string
region: string
count: string
date1: string
date2: string
delivery: boolean
type: string[]
resource: string
desc: string
}
const formSize = ref('default')
const ruleFormRef = ref<FormInstance>()
const ruleForm = reactive({
const ruleForm = reactive<RuleForm>({
name: 'Hello',
region: '',
count: '',
@ -97,7 +109,7 @@ const ruleForm = reactive({
desc: '',
})
const rules = reactive<FormRules>({
const rules = reactive<FormRules<RuleForm>>({
name: [
{ required: true, message: 'Please input Activity name', trigger: 'blur' },
{ min: 3, max: 5, message: 'Length should be 3 to 5', trigger: 'blur' },

View File

@ -6,6 +6,7 @@ import type {
} from 'async-validator'
import type { ComponentSize } from '@element-plus/constants'
import type { Arrayable } from '@element-plus/utils'
import type { MaybeRef } from '@vueuse/core'
import type {
FormItemProp,
FormItemProps,
@ -19,7 +20,82 @@ export type FormLabelWidthContext = ReturnType<typeof useFormLabelWidth>
export interface FormItemRule extends RuleItem {
trigger?: Arrayable<string>
}
export type FormRules = Partial<Record<string, Arrayable<FormItemRule>>>
type Primitive = null | undefined | string | number | boolean | symbol | bigint
/**
* Check whether it is tuple
*
* 检查是否为元组
*
* @example
* IsTuple<[1, 2, 3]> => true
* IsTuple<Array[number]> => false
*/
type IsTuple<T extends ReadonlyArray<any>> = number extends T['length']
? false
: true
/**
* Array method key
*
* 数组方法键
*/
type ArrayMethodKey = keyof any[]
/**
* Tuple index key
*
* 元组下标键
*
* @example
* TupleKey<[1, 2, 3]> => '0' | '1' | '2'
*/
type TupleKey<T extends ReadonlyArray<any>> = Exclude<keyof T, ArrayMethodKey>
/**
* Array index key
*
* 数组下标键
*/
type ArrayKey = number
/**
* Helper type for recursively constructing paths through a type
*
* 用于通过一个类型递归构建路径的辅助类型
*/
type PathImpl<K extends string | number, V> = V extends Primitive
? `${K}`
: `${K}` | `${K}.${Path<V>}`
/**
* Type which collects all paths through a type
*
* 通过一个类型收集所有路径的类型
*
* @see {@link FieldPath}
*/
type Path<T> = T extends ReadonlyArray<infer V>
? IsTuple<T> extends true
? {
[K in TupleKey<T>]-?: PathImpl<Exclude<K, symbol>, T[K]>
}[TupleKey<T>] // tuple
: PathImpl<ArrayKey, V> // array
: {
[K in keyof T]-?: PathImpl<Exclude<K, symbol>, T[K]>
}[keyof T] // object
/**
* Type which collects all paths through a type
*
* 通过一个类型收集所有路径的类型
*
* @example
* FieldPath<{ 1: number; a: number; b: string; c: { d: number; e: string }; f: [{ value: string }]; g: { value: string }[] }> => '1' | 'a' | 'b' | 'c' | 'f' | 'g' | 'c.d' | 'c.e' | 'f.0' | 'f.0.value' | 'g.number' | 'g.number.value'
*/
type FieldPath<T> = T extends object ? Path<T> : never
export type FormRules<
T extends MaybeRef<Record<string, any> | string> = string
> = Partial<
Record<
UnwrapRef<T> extends string ? UnwrapRef<T> : FieldPath<UnwrapRef<T>>,
Arrayable<FormItemRule>
>
>
export type FormValidationResult = Promise<boolean>
export type FormValidateCallback = (