Created
October 10, 2024 12:14
-
-
Save maradondt/e690b8d983ceaa987f90746aa3a1b012 to your computer and use it in GitHub Desktop.
yup custom validation hook
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable @typescript-eslint/no-explicit-any */ | |
/* eslint-disable @typescript-eslint/no-unused-vars */ | |
import { set } from 'lodash'; | |
import { useMemo } from 'react'; | |
import { Schema, ValidationError } from 'yup'; | |
/** | |
* Sets the `innerError.message` in an `errors` object at the key | |
* defined by `innerError.path`. | |
* @param {Object} errors The object to set the error in. | |
* @param {{ path: string, message: string }} innerError A `yup` field error. | |
* @returns {Object} The result of setting the new error message onto `errors`. | |
*/ | |
const setInError = <T extends Record<string, any>>( | |
errors: T, | |
innerError: ValidationError | |
): { [key in keyof T]: string } => { | |
if (!innerError.path) return errors; | |
return set(errors, innerError.path, innerError.message); | |
}; | |
/** | |
* Empty object map with no prototype. Used as default | |
* value for reducing the `err.inner` array of errors | |
* from a `yup~ValidationError`. | |
* @type {Object} | |
*/ | |
const emptyObj = Object.create(null); | |
// type Primitive = number | string | boolean; | |
type ObjectErrors<T> = { | |
[key in keyof T]?: T[key] extends object ? ObjectErrors<T[key]> : string | null; | |
}; | |
export type ValidationResult<T> = (T extends object ? ObjectErrors<T> : unknown) | null; | |
/** | |
* Takes a `yup` validation schema and returns a function that expects | |
* a map of values to validate. If the validation passes, the function resolves to `null` | |
* (signalling that the values are valid). If the validation doesn't pass, it resolves | |
* to a map of invalid field names to errors. | |
* @param {import('yup').ObjectSchema} schema `yup` schema definition. | |
* @returns {(values: Object) => Promise<?Object>} An async function that expects some `values` | |
* and resolves to either `null` or a map of field names to error messages. | |
*/ | |
export const makeValidate = (schema?: Schema) => { | |
if (!schema) return <T extends object = object>(_obj: T) => Promise.resolve(null); | |
return async function validate<T extends object = object>(values: T): Promise<ValidationResult<T>> { | |
try { | |
const resp = await schema.validate(values, { abortEarly: false }); | |
return null; | |
} catch (err) { | |
const error = err as ValidationError; | |
return error.inner.reduce((acc, err) => setInError<T>(acc, err), emptyObj); | |
} | |
}; | |
}; | |
export function useValidationSchema(schema?: Schema) { | |
const validate = useMemo(() => makeValidate(schema), [schema]); | |
return validate; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment