diff --git a/.changeset/wicked-ravens-shout.md b/.changeset/wicked-ravens-shout.md new file mode 100644 index 000000000..b3d43575f --- /dev/null +++ b/.changeset/wicked-ravens-shout.md @@ -0,0 +1,6 @@ +--- +'@tanstack/react-form': patch +'@tanstack/form-core': patch +--- + +Fix issues with methods not being present in React adapter diff --git a/packages/form-core/src/FieldApi.ts b/packages/form-core/src/FieldApi.ts index 7a97afe71..63d3066b1 100644 --- a/packages/form-core/src/FieldApi.ts +++ b/packages/form-core/src/FieldApi.ts @@ -962,6 +962,11 @@ export type AnyFieldApi = FieldApi< any > +/** + * We cannot use methods and must use arrow functions. Otherwise, our React adapters + * will break due to loss of the method when using spread. + */ + /** * A class representing the API for managing a form field. * @@ -1908,7 +1913,7 @@ export class FieldApi< /** * Updates the field's errorMap */ - setErrorMap( + setErrorMap = ( errorMap: ValidationErrorMap< UnwrapFieldValidateOrFn, UnwrapFieldValidateOrFn, @@ -1920,7 +1925,7 @@ export class FieldApi< UnwrapFieldValidateOrFn, UnwrapFieldAsyncValidateOrFn >, - ) { + ) => { this.setMeta((prev) => ({ ...prev, errorMap: { @@ -1997,7 +2002,7 @@ export class FieldApi< /** * @private */ - triggerOnChangeListener() { + triggerOnChangeListener = () => { const formDebounceMs = this.form.options.listeners?.onChangeDebounceMs if (formDebounceMs && formDebounceMs > 0) { if (this.timeoutIds.formListeners.change) { diff --git a/packages/form-core/src/FormApi.ts b/packages/form-core/src/FormApi.ts index e7e0dd08b..7daa493d5 100644 --- a/packages/form-core/src/FormApi.ts +++ b/packages/form-core/src/FormApi.ts @@ -870,6 +870,11 @@ export type AnyFormApi = FormApi< any > +/** + * We cannot use methods and must use arrow functions. Otherwise, our React adapters + * will break due to loss of the method when using spread. + */ + /** * A class representing the Form API. It handles the logic and interactions with the form state. * @@ -2016,12 +2021,17 @@ export class FormApi< return this.validateAsync(cause) } + // Needs to edgecase in the React adapter specifically to avoid type errors + handleSubmit(): Promise + handleSubmit(submitMeta: TSubmitMeta): Promise + handleSubmit(submitMeta?: TSubmitMeta): Promise { + return this._handleSubmit(submitMeta) + } + /** * Handles the form submission, performs validation, and calls the appropriate onSubmit or onSubmitInvalid callbacks. */ - handleSubmit(): Promise - handleSubmit(submitMeta: TSubmitMeta): Promise - async handleSubmit(submitMeta?: TSubmitMeta): Promise { + _handleSubmit = async (submitMeta?: TSubmitMeta): Promise => { this.baseStore.setState((old) => ({ ...old, // Submission attempts mark the form as not submitted @@ -2539,7 +2549,7 @@ export class FormApi< /** * Updates the form's errorMap */ - setErrorMap( + setErrorMap = ( errorMap: FormValidationErrorMap< TFormData, UnwrapFormValidateOrFn, @@ -2553,7 +2563,7 @@ export class FormApi< UnwrapFormAsyncValidateOrFn, UnwrapFormAsyncValidateOrFn >, - ) { + ) => { batch(() => { Object.entries(errorMap).forEach(([key, value]) => { const errorMapKey = key as ValidationErrorMapKeys diff --git a/packages/react-form/src/useForm.tsx b/packages/react-form/src/useForm.tsx index 59b2c5402..bd7f4cb4f 100644 --- a/packages/react-form/src/useForm.tsx +++ b/packages/react-form/src/useForm.tsx @@ -226,6 +226,9 @@ export function useForm< TSubmitMeta > = { ...formApi, + handleSubmit: ((...props: never[]) => { + formApi._handleSubmit(...props) + }) as typeof formApi.handleSubmit, // We must add all `get`ters from `core`'s `FormApi` here, as otherwise the spread operator won't catch those get formId(): string { return formApi._formId