validierung
Version:
Vue composition function for form validation
372 lines (362 loc) • 9.2 kB
TypeScript
import { Ref, UnwrapRef, ComputedRef } from 'vue-demi'
type AnyFunction = (...args: any[]) => any
type DeepIndex<
T,
Keys extends readonly PropertyKey[],
R = unknown
> = Keys extends [infer First, ...infer Rest]
? First extends keyof T
? Rest extends readonly PropertyKey[]
? DeepIndex<T[First], Rest>
: R
: R
: T
type MaybeRef<T> = T extends Ref<infer V> ? T | V : Ref<T> | T
type ExcludePrimitives<T> = T extends AnyFunction
? never
: T extends object
? T
: never
type DeepPartial<T extends object> = T extends readonly any[]
? {
[K in keyof T]: DeepPartialImpl<T[K]>
}
: {
[K in keyof T]?: DeepPartialImpl<T[K]> | undefined
}
type DeepPartialImpl<T> = T extends AnyFunction
? T
: T extends object
? DeepPartial<T>
: T
type ValidationBehaviorString = keyof ValidationBehaviorFunctions
interface ValidationBehaviorFunctions {}
type ValidationBehaviorInfo<T = any> = {
/**
* `True` if the paired rule of this behavior has an error.
*/
hasError: boolean
/**
* The touched state of the field.
*/
touched: boolean
/**
* The dirty state of the field.
*/
dirty: boolean
/**
* `True` if the validation was triggered with the `force` flag.
*/
force: boolean
/**
* `True` if the validation was triggered with the `submit` flag.
*/
submit: boolean
/**
* The `$value` property of the field.
*/
value: T
}
type ValidationBehaviorFunction = (info: ValidationBehaviorInfo) => boolean
type ValidationBehavior = ValidationBehaviorString | ValidationBehaviorFunction
type SimpleRule<TParam = any> = (value: TParam) => any
type KeyedRule<TParams extends readonly any[] = any[]> = (
...values: [...TParams]
) => any
type RuleWithKey<T extends readonly any[] = any[]> = {
key: string
rule?: KeyedRule<T>
}
type FieldSimpleRule<TParam = any> =
| SimpleRule<TParam>
| [
validationBehavior: ValidationBehavior,
rule: SimpleRule<TParam>,
debounce?: number
]
| [rule: SimpleRule<TParam>, debounce: number]
type FieldKeyedRule<TParams extends readonly any[]> =
| RuleWithKey<TParams>
| [
validationBehavior: ValidationBehavior,
rule: RuleWithKey<TParams>,
debounce?: number
]
| [rule: RuleWithKey<TParams>, debounce: number]
type FieldRule<TSimpleParams, TKeyedParams extends readonly any[] = any[]> =
| FieldSimpleRule<UnwrapRef<TSimpleParams>>
| FieldKeyedRule<TKeyedParams>
type ValidateFieldsPredicateParameter = {
key: string
value: any
path: string[]
}
type ValidateFieldsPredicate = (
value: ValidateFieldsPredicateParameter
) => boolean
type Field<T, E extends object = Record<string, never>> = {
/**
* The field's default value.
*/
$value: MaybeRef<T>
/**
* Rules to use for validation.
*/
$rules?: FieldRule<T>[]
} & (E extends Record<string, never> ? unknown : E)
type ValidateOptions = {
/**
* Set the field touched when called.
*
* @default true
*/
setTouched?: boolean
/**
* Validate with the `force` flag set.
*
* @default true
*/
force?: boolean
}
type TransformedField<T, E extends object = Record<string, never>> = {
/**
* The unique id of this field.
*/
$uid: number
/**
* The current field's value.
*/
$value: T
/**
* A list of validation error messages.
*/
$errors: string[]
/**
* The error status of this field.
*/
$hasError: boolean
/**
* `True` while this field has any pending rules.
*/
$validating: boolean
/**
* `True` if the field is touched. In most cases,
* this value should be set together with the `blur` event.
* Either through `$validate` or manually.
*/
$touched: boolean
/**
* `True` if the `$value` of this field has changed at least once.
*/
$dirty: boolean
/**
* Validate this field.
*
* @param options - Validate options to use
* @default
* ```
* { setTouched: true, force: true }
* ```
*/
$validate(options?: ValidateOptions): Promise<void>
} & (E extends Record<string, never> ? unknown : UnwrapRef<E>)
/**
* Unwrap the `$value` property of all fields in `FormData`.
*/
type ResultFormData<FormData> = FormData extends any
? {
[K in keyof FormData]: ResultFormDataImpl<FormData[K]>
}
: never
type ResultFormDataImpl<T> = T extends {
$value: infer V
}
? UnwrapRef<Exclude<MaybeRef<V>, Ref>>
: T extends object
? ResultFormData<T>
: T
/**
* Receive the name of every field in `FormData` as a union of strings.
*/
type FieldNames<FormData extends object> = FieldNamesImpl<FormData, never>
type FieldNamesImpl<FormData, K> = ExcludePrimitives<FormData> extends never
? never
: FormData extends {
$value: any
}
? K
: FormData extends readonly (infer A)[]
? FieldNamesImpl<A, K>
: {
[K in keyof FormData]-?: ExcludePrimitives<FormData[K]> extends {
$value: any
}
? K
: FieldNamesImpl<ExcludePrimitives<FormData[K]>, K>
}[keyof FormData]
/**
* Transforms every field in `FormData` into transformed fields.
*/
type TransformFormData<FormData> = FormData extends any
? {
[K in keyof FormData]: TransformFormDataImpl<FormData[K]>
}
: never
type TransformFormDataImpl<T> = T extends {
$value: infer V
}
? TransformedField<
UnwrapRef<Exclude<MaybeRef<V>, Ref>>,
Omit<T, '$value' | '$rules'>
>
: T extends object
? TransformFormData<T>
: T
/**
* Vue composition function for form validation.
* For type inference in `useValidation` make sure to define the structure of your
* form data upfront and pass it as the generic parameter `FormData`.
*
* @param formData - The structure of your form data
*
* @example
* ```
* type FormData = {
* name: Field<string>,
* password: Field<string>
* }
*
* const { form } = useValidation<FormData>({
* name: {
* $value: '',
* $rules: []
* },
* password: {
* $value: '',
* $rules: []
* }
* })
* ```
*/
declare function useValidation<FormData extends object>(
formData: FormData
): UseValidation<FormData>
type UseValidation<FormData extends object> = {
/**
* A transformed reactive form data object.
*/
form: TransformFormData<FormData>
/**
* `True` during validation after calling `validateFields` when there were rules returning a `Promise`.
*/
submitting: Ref<boolean>
/**
* `True` while the form has any pending rules.
*/
validating: ComputedRef<boolean>
/**
* `True` if the form has any error.
*/
hasError: ComputedRef<boolean>
/**
* All current validation error messages.
*/
errors: ComputedRef<string[]>
/**
* Validate all fields and return a `Promise` containing the resulting form data.
*
* @param options - Options to use for validation
* @throws `ValidationError`
*/
validateFields(options?: {
/**
* A list of field names to validate.
*
* @default
* ```
* undefined // meaning validate all
* ```
*/
names?: FieldNames<FormData>[]
/**
* Filter which values to keep in the resulting form data.
* Used like `Array.prototype.filter` but for objects.
*
* @default
* ```
* () => true // meaning keep all
* ```
*/
predicate?: ValidateFieldsPredicate
}): Promise<ResultFormData<FormData>>
/**
* Reset all fields to their default value or pass an object to set specific values.
* It will not create new fields not present in the form data initially.
*
* @param formData - Form data to set specific values. It has the same structure as the object passed to `useValidation`
*/
resetFields(formData?: DeepPartial<ResultFormData<FormData>>): void
/**
* Adds a new value to the form data.
*
* @param path - A path for the new value
* @param value - The value to add
*/
add<Keys extends readonly (string | number)[]>(
path: readonly [...Keys],
value: DeepIndex<FormData, Keys> extends (infer TArray)[]
? TArray
: DeepIndex<FormData, Keys>
): void
/**
* Removes a value from the form data.
*
* @param path - A path to the value to remove
*/
remove(path: (string | number)[]): void
}
type Configuration = {
defaultValidationBehavior: ValidationBehaviorString
validationBehavior: {
[K in ValidationBehaviorString]: ValidationBehaviorFunction
}
}
type Validation = {
install(): void
}
/**
* Configure the validation behavior of `useValidation`.
*
* @param configuration - The form validation configuration
*/
declare function createValidation(configuration: Configuration): Validation
declare class ValidationError extends Error {
constructor()
}
export {
AnyFunction,
DeepPartial,
ExcludePrimitives,
Field,
FieldKeyedRule,
FieldNames,
FieldSimpleRule,
KeyedRule,
ResultFormData,
SimpleRule,
TransformFormData,
TransformedField,
UseValidation,
ValidateFieldsPredicate,
ValidateFieldsPredicateParameter,
ValidateOptions,
Validation,
ValidationBehavior,
ValidationBehaviorFunction,
ValidationBehaviorFunctions,
ValidationBehaviorInfo,
ValidationBehaviorString,
ValidationError,
createValidation,
useValidation
}