vue3-form-validation
Version:
Vue composition function for form validation
372 lines (362 loc) • 9.61 kB
TypeScript
import { Ref, UnwrapRef, ComputedRef, Plugin } from 'vue'
declare type Key = string | number
declare type DeepIndex<T, Ks extends readonly Key[], R = unknown> = Ks extends [
infer First,
...infer Rest
]
? First extends keyof T
? Rest extends readonly Key[]
? DeepIndex<T[First], Rest>
: R
: R
: T
declare type MaybeRef<T> = T extends Ref<infer V> ? T | V : Ref<T> | T
declare type DeepIteratorResult = {
key: string
value: any
parent: any
path: string[]
isLeaf: boolean
}
declare type ValidationBehaviorString = keyof CustomValidationBehaviorFunctions
interface CustomValidationBehaviorFunctions {}
declare 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
}
declare type ValidationBehaviorFunction = (info: ValidationBehaviorInfo) => any
declare type ValidationBehavior =
| ValidationBehaviorString
| ValidationBehaviorFunction
declare type SimpleRule<TParameter = any> = (...value: TParameter[]) => any
declare type KeyedRule<TParameters extends readonly any[] = any[]> = (
...values: [...TParameters]
) => any
declare type RuleWithKey<T extends readonly any[] = any[]> = {
key: string
rule?: KeyedRule<T>
}
declare type FieldSimpleRule<TParameter = any> =
| SimpleRule<TParameter>
| [
validationBehavior: ValidationBehavior,
rule: SimpleRule<TParameter>,
debounce?: number
]
| [rule: SimpleRule<TParameter>, debounce: number]
declare type FieldRuleWithKey<TParameters extends readonly any[]> =
| RuleWithKey<TParameters>
| [
validationBehavior: ValidationBehavior,
rule: RuleWithKey<TParameters>,
debounce?: number
]
| [rule: RuleWithKey<TParameters>, debounce: number]
declare type FieldRule<
TSimpleParameter,
TKeyedParameters extends readonly any[] = any[]
> =
| FieldSimpleRule<
TSimpleParameter extends any[]
? TSimpleParameter
: UnwrapRef<TSimpleParameter>
>
| FieldRuleWithKey<TKeyedParameters>
declare type Field<
TValue,
TExtra extends Record<string, unknown> = Record<string, never>
> = {
/**
* The field's default value.
*/
$value: MaybeRef<TValue>
/**
* Rules to use for validation.
*/
$rules?: FieldRule<TValue>[]
} & (TExtra extends Record<string, never> ? unknown : TExtra)
declare type ValidateOptions = {
/**
* Set the field touched when called.
*
* @default true
*/
setTouched?: boolean
/**
* Validate with the `force` flag set.
*
* @default true
*/
force?: boolean
}
declare type TransformedField<
TValue,
TExtra extends Record<string, unknown> = Record<string, never>
> = {
/**
* The unique id of this field.
*/
$uid: number
/**
* The current field's value.
*/
$value: TValue
/**
* A list of validation error messages local to this field without `null` values.
*/
$errors: string[]
/**
* The field's raw error messages one for each rule and `null` if there is no error.
*/
$rawErrors: (string | null)[]
/**
* `True` while this field has any error.
*/
$hasError: boolean
/**
* `True` while this field has any pending rules.
*/
$validating: boolean
/**
* `True` if the field is touched.
*
* @remarks
* 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>
} & (TExtra extends Record<string, never> ? unknown : UnwrapRef<TExtra>)
/**
* Unwrap the `$value` property of all fields in `FormData`.
*/
declare type ResultFormData<FormData> = FormData extends any
? {
[K in keyof FormData]: Exclude<FormData[K], undefined> extends {
$value: infer TValue
}
? UnwrapRef<Exclude<TValue, Ref>>
: Exclude<FormData[K], undefined> extends object
? ResultFormData<FormData[K]>
: FormData[K]
}
: never
/**
* Receive the name of every field in `FormData` as a union of strings.
*/
declare type FieldNames<FormData> = FormData extends (infer TArray)[]
? FieldNames<TArray>
: {
[K in keyof FormData]-?: Exclude<FormData[K], undefined> extends {
$value: any
}
? K
: FieldNames<FormData[K]>
}[keyof FormData]
/**
* Transforms every field in `FormData` into transformed fields.
*/
declare type TransformFormData<FormData> = FormData extends any
? {
[K in keyof FormData]: Exclude<FormData[K], undefined> extends {
$value: infer TValue
}
? TransformedField<
UnwrapRef<Exclude<TValue, Ref>>,
Omit<Exclude<FormData[K], undefined>, '$value' | '$rules'>
>
: Exclude<FormData[K], undefined> extends object
? TransformFormData<FormData[K]>
: FormData[K]
}
: never
/**
* Vue composition function for form validation.
*
* @remarks
* 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>
declare 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.
*
* @remarks
* Used like `Array.prototype.filter`.
*
* @default
* ```
* () => true // meaning keep all
* ```
*/
predicate?: (
value: Omit<DeepIteratorResult, 'isLeaf' | 'parent'>
) => unknown
}): Promise<ResultFormData<FormData>>
/**
* Reset all fields to their default value or pass an object to set specific values.
*
* @remarks
* It will not create any 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?: Partial<ResultFormData<FormData>>): void
/**
* Adds a new property to the form data.
*
* @remarks
* Fields with a `$value` are transformed.
*
* @param path - A path of `string` and `numbers`
* @param value - The value to add at the specified path
*/
add<Keys extends readonly (string | number)[]>(
path: readonly [...Keys],
value: DeepIndex<FormData, Keys> extends (infer TArray)[]
? TArray
: DeepIndex<FormData, Keys>
): void
/**
* Removes a property from the form data.
*
* @param path - A path of `string` and `numbers` to the property to remove
*/
remove(path: (string | number)[]): void
}
declare type ConfigurationValidationBehavior = {
[K in ValidationBehaviorString]: ValidationBehaviorFunction
}
declare type Configuration =
keyof CustomValidationBehaviorFunctions extends never
? {
defaultValidationBehavior: ValidationBehaviorString
validationBehavior?: ConfigurationValidationBehavior
}
: {
defaultValidationBehavior: ValidationBehaviorString
validationBehavior: ConfigurationValidationBehavior
}
/**
* Configure the validation behavior of `useValidation`.
*
* @param configuration - The form validation configuration
*/
declare function createValidation(configuration: Configuration): Plugin
declare class ValidationError extends Error {
constructor()
}
export {
CustomValidationBehaviorFunctions,
Field,
FieldNames,
KeyedRule,
ResultFormData,
SimpleRule,
TransformFormData,
TransformedField,
UseValidation,
ValidateOptions,
ValidationBehavior,
ValidationBehaviorFunction,
ValidationBehaviorInfo,
ValidationBehaviorString,
ValidationError,
createValidation,
useValidation
}