From 9e0a661513af75d1b848e5be7a4916c53b78760f Mon Sep 17 00:00:00 2001 From: Marco Boninsegni Date: Wed, 2 Aug 2023 05:13:23 +0100 Subject: [PATCH] types: Align FormikHelpers and FieldHelper types to useFormik ones (#3843) This is yet another PR around TypeScript. The inferred types for the helpers in `useFormik` are the correct ones and should be used everywhere. See ``` export declare function useFormik({ validateOnChange, validateOnBlur, validateOnMount, isInitialValid, enableReinitialize, onSubmit, ...rest }: FormikConfig): { [...redacted for readability...] setFieldTouched: (field: string, touched?: boolean, shouldValidate?: boolean) => Promise> | Promise; setFieldValue: (field: string, value: any, shouldValidate?: boolean) => Promise> | Promise; setFieldError: (field: string, value: string | undefined) => void; setStatus: (status: any) => void; setSubmitting: (isSubmitting: boolean) => void; setTouched: (touched: FormikTouched, shouldValidate?: boolean) => Promise> | Promise; setValues: (values: React.SetStateAction, shouldValidate?: boolean) => Promise> | Promise; submitForm: () => Promise; validateForm: (values?: Values) => Promise>; validateField: (name: string) => Promise | Promise; [...redacted for readability...] }; ``` Having the correct types, and the awaiting these helpers helps with otherwise possible race conditions when used in an imperative way, like so ``` const handleChange = ({ target }) => { await setFieldTouched('fieldName', true, false) await setFieldValue('fieldName', target.value, false) await validateField('fieldName') } ``` --- .changeset/nervous-flowers-rule.md | 5 +++++ docs/api/formik.md | 10 ++++++++-- docs/api/useField.md | 6 +++++- packages/formik/src/types.tsx | 12 ++++++------ 4 files changed, 24 insertions(+), 9 deletions(-) create mode 100644 .changeset/nervous-flowers-rule.md diff --git a/.changeset/nervous-flowers-rule.md b/.changeset/nervous-flowers-rule.md new file mode 100644 index 000000000..032067e07 --- /dev/null +++ b/.changeset/nervous-flowers-rule.md @@ -0,0 +1,5 @@ +--- +'formik': patch +--- + +Fix FormikHelper and FieldHelperProps types diff --git a/docs/api/formik.md b/docs/api/formik.md index 0dfec7603..4da6b9ea2 100644 --- a/docs/api/formik.md +++ b/docs/api/formik.md @@ -177,11 +177,13 @@ Set `errors` imperatively. Set the error message of a field imperatively. `field` should match the key of `errors` you wish to update. Useful for creating custom input error handlers. -#### `setFieldTouched: (field: string, isTouched?: boolean, shouldValidate?: boolean) => void` +#### `setFieldTouched: (field: string, isTouched?: boolean, shouldValidate?: boolean) => Promise` Set the touched state of a field imperatively. `field` should match the key of `touched` you wish to update. Useful for creating custom input blur handlers. Calling this method will trigger validation to run if `validateOnBlur` is set to `true` (which it is by default). `isTouched` defaults to `true` if not specified. You can also explicitly prevent/skip validation by passing a third argument as `false`. +If `validateOnBlur` is set to `true` and there are errors, they will be resolved in the returned `Promise`. + #### `submitForm: () => Promise` Trigger a form submission. The promise will be rejected if form is invalid. @@ -208,14 +210,18 @@ use it to pass API responses back into your component in `handleSubmit`. Set `isSubmitting` imperatively. You would call it with `setSubmitting(false)` in your `onSubmit` handler to finish the cycle. To learn more about the submission process, see [Form Submission](../guides/form-submission.md). -#### `setTouched: (fields: { [field: string]: boolean }, shouldValidate?: boolean) => void` +#### `setTouched: (fields: { [field: string]: boolean }, shouldValidate?: boolean) => Promise` Set `touched` imperatively. Calling this will trigger validation to run if `validateOnBlur` is set to `true` (which it is by default). You can also explicitly prevent/skip validation by passing a second argument as `false`. +If `validateOnBlur` is set to `true` and there are errors, they will be resolved in the returned `Promise`. + #### `setValues: (fields: React.SetStateAction<{ [field: string]: any }>, shouldValidate?: boolean) => void` Set `values` imperatively. Calling this will trigger validation to run if `validateOnChange` is set to `true` (which it is by default). You can also explicitly prevent/skip validation by passing a second argument as `false`. +If `validateOnChange` is set to `true` and there are errors, they will be resolved in the returned `Promise`. + #### `status?: any` A top-level status object that you can use to represent form state that can't diff --git a/docs/api/useField.md b/docs/api/useField.md index b9065b432..e5e3dd6aa 100644 --- a/docs/api/useField.md +++ b/docs/api/useField.md @@ -159,6 +159,10 @@ An object that contains relevant computed metadata about a field. More specifica An object that contains helper functions which you can use to imperatively change the value, error value or touched status for the field in question. This is useful for components which need to change a field's status directly, without triggering change or blur events. -- `setValue(value: any, shouldValidate?: boolean): void` - A function to change the field's value. Calling this will trigger validation to run if `validateOnChange` is set to `true` (which it is by default). You can also explicitly prevent/skip validation by passing a second argument as `false`. +- `setValue(value: any, shouldValidate?: boolean): Promise` - A function to change the field's value. Calling this will trigger validation to run if `validateOnChange` is set to `true` (which it is by default). You can also explicitly prevent/skip validation by passing a second argument as `false`. +If `validateOnChange` is set to `true` and there are errors, they will be resolved in the returned `Promise`. + - `setTouched(value: boolean, shouldValidate?: boolean): void` - A function to change the field's touched status. Calling this will trigger validation to run if `validateOnBlur` is set to `true` (which it is by default). You can also explicitly prevent/skip validation by passing a second argument as `false`. +If `validateOnBlur` is set to `true` and there are errors, they will be resolved in the returned `Promise`. + - `setError(value: any): void` - A function to change the field's error value diff --git a/packages/formik/src/types.tsx b/packages/formik/src/types.tsx index 9586fe865..71db6792c 100644 --- a/packages/formik/src/types.tsx +++ b/packages/formik/src/types.tsx @@ -86,12 +86,12 @@ export interface FormikHelpers { setTouched: ( touched: FormikTouched, shouldValidate?: boolean - ) => void; + ) => Promise>; /** Manually set values object */ setValues: ( values: React.SetStateAction, shouldValidate?: boolean - ) => void; + ) => Promise>; /** Set value of form field directly */ setFieldValue: ( field: string, @@ -105,11 +105,11 @@ export interface FormikHelpers { field: string, isTouched?: boolean, shouldValidate?: boolean - ) => void; + ) => Promise>; /** Validate form values */ validateForm: (values?: any) => Promise>; /** Validate field value */ - validateField: (field: string) => void; + validateField: (field: string) => Promise | Promise; /** Reset form */ resetForm: (nextState?: Partial>) => void; /** Submit the form imperatively */ @@ -302,9 +302,9 @@ export interface FieldMetaProps { /** Imperative handles to change a field's value, error and touched */ export interface FieldHelperProps { /** Set the field's value */ - setValue: (value: Value, shouldValidate?: boolean) => void; + setValue: (value: Value, shouldValidate?: boolean) => Promise>; /** Set the field's touched value */ - setTouched: (value: boolean, shouldValidate?: boolean) => void; + setTouched: (value: boolean, shouldValidate?: boolean) => Promise>; /** Set the field's error value */ setError: (value: string | undefined) => void; }