Skip to content

fix(react-form): subscribe to full meta object#1981

Open
ws-rush wants to merge 22 commits intoTanStack:mainfrom
wusabyRush:issue-1980-fix-custom-meta-updates-18083788771914964547
Open

fix(react-form): subscribe to full meta object#1981
ws-rush wants to merge 22 commits intoTanStack:mainfrom
wusabyRush:issue-1980-fix-custom-meta-updates-18083788771914964547

Conversation

@ws-rush
Copy link
Copy Markdown

@ws-rush ws-rush commented Jan 6, 2026

Fixes issue #1980 where custom field meta properties were not triggering updates in useField.
Replaced granular meta subscriptions with a full state.meta subscription in useField hook.
Optimized FormApi.setFieldValue in @tanstack/form-core to avoid unnecessary meta updates, preserving performance optimizations for array fields.
Added regression test and updated existing tests.


PR created automatically by Jules for task 18083788771914964547 started by @ws-rush

Summary by CodeRabbit

  • New Features

    • Form-level default field metadata and typed support for custom field meta across form and field APIs.
  • Bug Fixes

    • Field metadata subscriptions now surface custom meta properties reliably on mount and updates.
    • set-field operations avoid forcing meta changes when status already reflects touched/dirty.
  • Tests

    • Added runtime and type tests for custom meta behavior and mount-time visibility.
    • Relaxed array-field render-count expectation in StrictMode.

… custom meta properties

This commit modifies `useField` to subscribe to the entire `state.meta` object instead of granular properties. This ensures that custom meta properties (like `hidden`) added by users trigger re-renders when updated.

To mitigate performance regressions (specifically array fields re-rendering on every child update due to `isDirty`/`isTouched` refresh), `FormApi.setFieldValue` is optimized to skip `setFieldMeta` if the meta state is already correct. This ensures `meta` object reference stability when relevant state hasn't changed.

Added regression test `tests/issue-1980.test.tsx`.
Updated `tests/useField.test.tsx` to accommodate the slight behavior change (initial re-render due to `isDefaultValue` change).
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Jan 6, 2026

🦋 Changeset detected

Latest commit: c8a45f1

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 13 packages
Name Type
@tanstack/react-form Patch
@tanstack/form-core Patch
@tanstack/react-form-nextjs Patch
@tanstack/react-form-remix Patch
@tanstack/react-form-start Patch
@tanstack/angular-form Patch
@tanstack/form-devtools Patch
@tanstack/lit-form Patch
@tanstack/solid-form Patch
@tanstack/svelte-form Patch
@tanstack/vue-form Patch
@tanstack/react-form-devtools Patch
@tanstack/solid-form-devtools Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

ws-rush and others added 7 commits January 6, 2026 19:39
… custom meta properties

This commit modifies `useField` to subscribe to the entire `state.meta` object instead of granular properties. This ensures that custom meta properties (like `hidden`) added by users trigger re-renders when updated.

To mitigate performance regressions (specifically array fields re-rendering on every child update due to `isDirty`/`isTouched` refresh), `FormApi.setFieldValue` is optimized to skip `setFieldMeta` if the meta state is already correct. This ensures `meta` object reference stability when relevant state hasn't changed.

Added regression test `tests/issue-1980.test.tsx`.
Updated `tests/useField.test.tsx` to accommodate the slight behavior change (initial re-render due to `isDefaultValue` change).
@ws-rush ws-rush force-pushed the issue-1980-fix-custom-meta-updates-18083788771914964547 branch from 60c8c31 to effb050 Compare January 10, 2026 10:51
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Consolidates meta subscription in useField to track the full meta object, adds form-level defaultMeta typing/merging, changes FormApi.setFieldValue to only update meta when it would change, and adds runtime and type tests plus changesets for custom field meta support.

Changes

Cohort / File(s) Summary
Changesets
\.changeset/issue-1980-fix.md, \.changeset/custom-field-meta.md
Adds changeset metadata marking @tanstack/react-form and @tanstack/form-core for patch releases and documents custom field meta behavior.
Core: Form API
packages/form-core/src/FormApi.ts
Introduces TFormMeta generic and defaultMeta option on FormOptions; setFieldValue now updates touch/dirty/onMount meta only when it would change existing meta.
Core: Field API
packages/form-core/src/FieldApi.ts
Loosens field meta typings to accept arbitrary extra keys and merges form-level defaultMeta into a field's initial meta at runtime.
React: useField hook
packages/react-form/src/useField.tsx
Replaces multiple per-meta subscriptions with a single state.meta selector; assigns meta from the reactive selector; updates memo deps; updates exported FieldComponent types to carry TFormMeta.
React: useForm typing/runtime cast
packages/react-form/src/useForm.tsx
Threads TFormMeta generics through public ReactFormApi/ReactFormExtendedApi types, adds a useForm overload requiring defaultMeta, and adjusts runtime cast when spreading Field props.
React: createFormHook typing tweak
packages/react-form/src/createFormHook.tsx
Adds TFormMeta generic propagation through useAppForm/AppFieldExtendedReactFormApi and applies a as never assertion for children(Object.assign(...)) to satisfy updated types.
Tests: runtime (new)
packages/react-form/tests/issue-1980.test.tsx
New RTL + Vitest test verifying initial-mount and reactive updates for inter-field meta (e.g., hidden) when meta depends on another field's value.
Tests: runtime update
packages/react-form/tests/useField.test.tsx
Relaxes array field render-count expectation to allow up to two extra renders while preserving correctness assertions.
Tests: type tests
packages/react-form/tests/useField.test-d.tsx, packages/react-form/tests/createFormHook.test-d.tsx
Adds compile-time type tests ensuring defaultMeta inference at form and field levels and correct getMeta/setMeta typings for custom meta (e.g., dataSource: Country[]).

Sequence Diagram(s)

sequenceDiagram
  participant ReactComponent as React Component
  participant useField as useField Hook
  participant FormCore as Form Core (FormApi / FieldApi)
  participant DOM as DOM / Renderer

  ReactComponent->>useField: mount Field component
  useField->>FormCore: subscribe to `field.state.meta` (single selector)
  useField->>FormCore: read other field value (e.g., color)
  useField->>FormCore: call setFieldMeta / setFieldValue (if needed)
  FormCore-->>useField: emit meta update notification
  useField->>DOM: update reactive meta -> re-render Field (show/hide)
  ReactComponent->>useField: user changes other field
  FormCore-->>useField: notify meta/state change for dependent field
  useField->>DOM: update DOM according to new meta
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇 I nibble at meta, weave it tight,

Defaults join fields in morning light.
Hooks subscribe to the whole, not parts,
Tests clap paws — types sing their hearts.
Hoppity hop, a patchy delight!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.69% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The PR description clearly explains the problem (custom meta properties not triggering updates), the solution (subscribe to full state.meta), and includes testing updates, but does not follow the repository's template structure with marked checklist items. Consider using the repository's description template with explicit checklist markers (- [x]) to confirm contribution guidelines and testing completion.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: replacing granular meta subscriptions with full meta object subscription in useField to fix custom field meta property updates.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/form-core/src/FormApi.ts`:
- Around line 2309-2327: getFieldMeta(field) can return undefined and the
current checks dereference meta (meta.isDirty / meta.errorMap) before falling
back, causing runtime errors; guard the lookup by assigning a safe fallback
(e.g., defaultFieldMeta) or check for meta existence before accessing
properties. Update the block around getFieldMeta(field) to use a local const
(e.g., const meta = this.getFieldMeta(field) ?? defaultFieldMeta) or change the
conditional to short-circuit when meta is falsy, and then call
setFieldMeta(field, prev => ...) as before; reference getFieldMeta,
meta.isDirty, meta.errorMap, and setFieldMeta in your change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 847a0459-ef08-4954-a800-2325dd7e2cbd

📥 Commits

Reviewing files that changed from the base of the PR and between 1cdd97a and 9c78f7c.

📒 Files selected for processing (5)
  • .changeset/issue-1980-fix.md
  • packages/form-core/src/FormApi.ts
  • packages/react-form/src/useField.tsx
  • packages/react-form/tests/issue-1980.test.tsx
  • packages/react-form/tests/useField.test.tsx

Comment on lines 2309 to +2327
if (!dontUpdateMeta) {
this.setFieldMeta(field, (prev) => ({
...prev,
isTouched: true,
isDirty: true,
errorMap: {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
...prev?.errorMap,
onMount: undefined,
},
}))
const meta = this.getFieldMeta(field)

if (
!meta?.isTouched ||
!meta.isDirty ||
meta.errorMap.onMount !== undefined
) {
this.setFieldMeta(field, (prev) => ({
...prev,
isTouched: true,
isDirty: true,
errorMap: {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
...prev?.errorMap,
onMount: undefined,
},
}))
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Guard the metadata lookup before dereferencing it.

getFieldMeta(field) can be undefined for fields that haven't been materialized yet, so meta.isDirty / meta.errorMap can throw before the fallback path runs. Default to defaultFieldMeta or add an explicit guard.

🔧 Suggested fix
-        const meta = this.getFieldMeta(field)
+        const meta = this.getFieldMeta(field) ?? defaultFieldMeta
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/form-core/src/FormApi.ts` around lines 2309 - 2327,
getFieldMeta(field) can return undefined and the current checks dereference meta
(meta.isDirty / meta.errorMap) before falling back, causing runtime errors;
guard the lookup by assigning a safe fallback (e.g., defaultFieldMeta) or check
for meta existence before accessing properties. Update the block around
getFieldMeta(field) to use a local const (e.g., const meta =
this.getFieldMeta(field) ?? defaultFieldMeta) or change the conditional to
short-circuit when meta is falsy, and then call setFieldMeta(field, prev => ...)
as before; reference getFieldMeta, meta.isDirty, meta.errorMap, and setFieldMeta
in your change.

@ws-rush
Copy link
Copy Markdown
Author

ws-rush commented Apr 29, 2026

support custom meta typing added as experiment, Remaining TODOs:

  1. Add exact typed form-level meta tests
    • Field callback typing is strong now.
    • form.getFieldMeta(...)? still has optional result because field meta may not exist yet.
    • Could add/verify autocomplete behavior for form.state.fieldMeta and form.getFieldMeta.
  2. Consider core-level generic support
    • Current strong inference is mostly wired in React types.
    • Other adapters do not get the same typed meta inference yet.
  3. Port to other adapters
    • Solid
    • Vue
    • Angular
    • Svelte
    • Lit
  4. Decide if custom meta should avoid Record<string, unknown>
    • index signature added to support arbitrary custom keys.
    • It helps property access but can weaken “unknown key should error” strictness.
  5. Derived meta write protection
    • changes prevents defaultMeta / setMeta from typing derived keys like isValid, errors.
    • Current implementation focuses on inference/autocomplete, not strict derived-key exclusion.
  6. Docs
    • Add docs showing:
  useForm({                                                                                                              
    defaultMeta: { disabled: false },                                                                                    
  })                                                                                                                     
                                                                                                                         
  <form.Field                                                                                                            
    name="countryId"                                                                                                     
    defaultMeta={{ dataSource: [] as Country[] }}                                                                        
  >                                                                                                                      

there is a lot of AI here so sure all thing need review

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/react-form/src/useForm.tsx (1)

22-45: Consider centralizing WidenMeta in one internal type utility.

WidenMeta now exists in both packages/react-form/src/useForm.tsx and packages/react-form/src/useField.tsx; extracting it reduces future type drift.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/react-form/src/useForm.tsx` around lines 22 - 45, WidenMeta is
duplicated across useForm.tsx and useField.tsx—extract it into a single internal
type utility (e.g., create a new internal types module) and replace the local
definitions in both files with an import of that shared WidenMeta; update usages
in FormApiWithCustomMeta and getFieldMeta to reference the centralized
WidenMeta, ensure the new module exports the type (or marks it internal) and run
type-check to fix any import/visibility issues.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/react-form/src/useForm.tsx`:
- Around line 22-45: WidenMeta is duplicated across useForm.tsx and
useField.tsx—extract it into a single internal type utility (e.g., create a new
internal types module) and replace the local definitions in both files with an
import of that shared WidenMeta; update usages in FormApiWithCustomMeta and
getFieldMeta to reference the centralized WidenMeta, ensure the new module
exports the type (or marks it internal) and run type-check to fix any
import/visibility issues.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3b31e1a6-9cdc-46ee-b2d0-0b6c10b22c66

📥 Commits

Reviewing files that changed from the base of the PR and between 9c78f7c and 2ae8b40.

📒 Files selected for processing (7)
  • .changeset/custom-field-meta.md
  • packages/form-core/src/FieldApi.ts
  • packages/form-core/src/FormApi.ts
  • packages/react-form/src/createFormHook.tsx
  • packages/react-form/src/useField.tsx
  • packages/react-form/src/useForm.tsx
  • packages/react-form/tests/useField.test-d.tsx
✅ Files skipped from review due to trivial changes (1)
  • .changeset/custom-field-meta.md

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/react-form/src/useForm.tsx (1)

418-420: Pragmatic type cast, consider documenting the reason.

The as any cast bypasses complex generic type checking for FieldComponent's 24+ type parameters. While this suppresses type errors at the spread site, call-site type checking is preserved since APIField's signature inherits from the typed FieldComponent.

Consider adding a brief comment explaining why the cast is necessary to help future maintainers.

📝 Suggested documentation
     extendedApi.Field = function APIField(props) {
+      // Cast needed: FieldComponent's complex generic constraints can't be fully
+      // expressed here; call-site type checking remains intact via the typed signature
       return <Field {...(props as any)} form={formApi} />
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/react-form/src/useForm.tsx` around lines 418 - 420, Add a brief
inline comment above the cast in extendedApi.Field explaining why the pragmatic
`as any` is required: note that FieldComponent has a very large generic
signature (24+ type parameters) which causes excessive TypeScript complexity at
the spread site, and that the cast only suppresses the spread-site generic
inference while preserving call-site type checking via APIField's signature;
reference the symbols extendedApi.Field, APIField, Field, and formApi in the
comment so future maintainers understand the trade-off and where to revisit if
type simplification or helper overloads are added.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/react-form/src/useForm.tsx`:
- Around line 418-420: Add a brief inline comment above the cast in
extendedApi.Field explaining why the pragmatic `as any` is required: note that
FieldComponent has a very large generic signature (24+ type parameters) which
causes excessive TypeScript complexity at the spread site, and that the cast
only suppresses the spread-site generic inference while preserving call-site
type checking via APIField's signature; reference the symbols extendedApi.Field,
APIField, Field, and formApi in the comment so future maintainers understand the
trade-off and where to revisit if type simplification or helper overloads are
added.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c34af65e-842b-40ef-b773-98a87a48b35c

📥 Commits

Reviewing files that changed from the base of the PR and between 2ae8b40 and 3c55618.

📒 Files selected for processing (2)
  • packages/react-form/src/useForm.tsx
  • packages/react-form/tests/useField.test-d.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/react-form/tests/useField.test-d.tsx

   Thread form-level custom meta through useAppForm, AppFieldExtendedReactFormApi,
   and FieldComponent so metadata inferred from formOptions({ defaultMeta }) is
   available in field render callbacks.

   Add regression coverage for useAppForm with formOptions and array-valued
   defaultMeta.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
packages/react-form/src/createFormHook.tsx (2)

320-371: Align useAppForm overloads with useForm to remove the double assertion.

At Line 357, as unknown as ReactFormExtendedApi<...> bypasses compile-time validation. The mismatch arises because useAppForm marks defaultMeta as optional (defaultMeta?: TFormMeta), while useForm's first overload requires it to be non-optional (defaultMeta: TFormMeta). The double assertion hides this contract drift.

Proposed refactor

Use function overloads to distinguish between when defaultMeta is explicitly provided vs. omitted, mirroring useForm's pattern:

-  function useAppForm<..., const TFormMeta extends object = {}>(
-    props: Omit<FormOptions<..., TFormMeta>, 'defaultMeta'> & {
-      defaultMeta?: TFormMeta
-    },
-  ): AppFieldExtendedReactFormApi<..., TFormMeta> {
-    const form = useForm(props) as unknown as ReactFormExtendedApi<..., TFormMeta>
+  // overload 1: defaultMeta provided => infer/preserve TFormMeta
+  function useAppForm<..., const TFormMeta extends object>(
+    props: Omit<FormOptions<..., TFormMeta>, 'defaultMeta'> & {
+      defaultMeta: TFormMeta
+    },
+  ): AppFieldExtendedReactFormApi<..., TFormMeta>
+
+  // overload 2: defaultMeta omitted => fallback meta type
+  function useAppForm<...>(
+    props: FormOptions<..., TSubmitMeta>,
+  ): AppFieldExtendedReactFormApi<..., {}>
+
+  function useAppForm(props: any): any {
+    const form = useForm(props)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/react-form/src/createFormHook.tsx` around lines 320 - 371, The
double-cast on the result of useForm in useAppForm hides a type-contract
mismatch caused by marking defaultMeta optional in useAppForm's props while
useForm's overload requires defaultMeta to be present; adjust useAppForm to
provide matching function overloads (mirror useForm's overloads) that
distinguish the case where defaultMeta is supplied vs omitted so the inferred
return type is ReactFormExtendedApi<...> without using "as unknown as
ReactFormExtendedApi"; update the signatures for useAppForm (and its props
generic) so callers that omit defaultMeta get the appropriate overload and the
implementation can call useForm without unsafe assertions.

389-389: Replace as never at the children boundary with an explicit merged type.

At line 389, as never suppresses type checks exactly where field and fieldComponents are merged and passed to user code. This weakens safety and makes regressions harder to catch.

Proposed refactor
-                {children(Object.assign(field, fieldComponents) as never)}
+                {children(
+                  Object.assign(field, fieldComponents) as typeof field &
+                    NoInfer<TComponents>
+                )}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/react-form/src/createFormHook.tsx` at line 389, The cast "as never"
at the children boundary suppresses type checking for the merged props
(children(Object.assign(field, fieldComponents) as never)); replace it with an
explicit merged type so callers get correct typings: define a merged
interface/type (e.g., MergedFieldProps = FieldProps & typeof fieldComponents or
a generic Merge<FieldProps, FieldComponentTypes>) that represents the
intersection of the runtime `field` shape and `fieldComponents`, and cast the
Object.assign result to that type before passing to `children`; also update the
`children` prop signature to accept this merged type (referencing the
`children`, `field`, and `fieldComponents` symbols in createFormHook.tsx).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/react-form/src/createFormHook.tsx`:
- Around line 320-371: The double-cast on the result of useForm in useAppForm
hides a type-contract mismatch caused by marking defaultMeta optional in
useAppForm's props while useForm's overload requires defaultMeta to be present;
adjust useAppForm to provide matching function overloads (mirror useForm's
overloads) that distinguish the case where defaultMeta is supplied vs omitted so
the inferred return type is ReactFormExtendedApi<...> without using "as unknown
as ReactFormExtendedApi"; update the signatures for useAppForm (and its props
generic) so callers that omit defaultMeta get the appropriate overload and the
implementation can call useForm without unsafe assertions.
- Line 389: The cast "as never" at the children boundary suppresses type
checking for the merged props (children(Object.assign(field, fieldComponents) as
never)); replace it with an explicit merged type so callers get correct typings:
define a merged interface/type (e.g., MergedFieldProps = FieldProps & typeof
fieldComponents or a generic Merge<FieldProps, FieldComponentTypes>) that
represents the intersection of the runtime `field` shape and `fieldComponents`,
and cast the Object.assign result to that type before passing to `children`;
also update the `children` prop signature to accept this merged type
(referencing the `children`, `field`, and `fieldComponents` symbols in
createFormHook.tsx).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5b579600-3809-4b8f-b352-432822630127

📥 Commits

Reviewing files that changed from the base of the PR and between 3c55618 and cdfa1f5.

📒 Files selected for processing (2)
  • packages/react-form/src/createFormHook.tsx
  • packages/react-form/tests/createFormHook.test-d.tsx
✅ Files skipped from review due to trivial changes (1)
  • packages/react-form/tests/createFormHook.test-d.tsx

…pForm

useAppForm was not forwarding TFormMeta to useForm, causing custom
meta properties (e.g. dataSource) to resolve as unknown in
form.AppField render props, getFieldMeta(), and state.fieldMeta.

- Pass TFormMeta explicitly when calling useForm inside useAppForm
- Intersect FormApiCustomMeta into AppFieldExtendedReactFormApi so
  getFieldMeta and state.fieldMeta carry the widened custom meta types
- Cast return to AppFieldExtendedReactFormApi to satisfy the widened
  fieldMeta signature without breaking FormApi structural compatibility
- Add type tests for form-level and field-level defaultMeta inference
  via both formOptions and direct props, using form.AppField
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/react-form/src/createFormHook.tsx`:
- Around line 185-201: The custom TFormMeta generic is being dropped by helper
types—update the helper signatures WithFormProps, withForm, and
useTypedAppFormContext to include a trailing generic parameter TFormMeta = {}
and thread that parameter into every instantiation of
AppFieldExtendedReactFormApi used in those helpers (i.e., add the trailing meta
type argument to AppFieldExtendedReactFormApi in the WithFormProps, withForm,
and useTypedAppFormContext definitions) so getFieldMeta/state.fieldMeta retain
the custom meta typing from createFormHook.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d1b7e613-6bb7-4f2f-baa6-ce0cc411a871

📥 Commits

Reviewing files that changed from the base of the PR and between cdfa1f5 and f75b547.

📒 Files selected for processing (2)
  • packages/react-form/src/createFormHook.tsx
  • packages/react-form/tests/createFormHook.test-d.tsx

Comment thread packages/react-form/src/createFormHook.tsx
ws-rush added 4 commits April 29, 2026 17:43
…field validators

- Thread TFormMeta through WithFormProps so forms with inferred
  defaultMeta can be passed to withForm components without type errors
- Field validators now receive a fieldApi whose getMeta() includes
  custom meta inferred from the form's defaultMeta
- Previously the validator's fieldApi was typed with the core FieldApi
  which has no awareness of custom meta, causing properties like
  dataSource to be typed as unknown
…field validators

- Thread TFormMeta through WithFormProps so forms with inferred
  defaultMeta can be passed to withForm components without type errors
- Field validators now receive a fieldApi whose getMeta() includes
  custom meta inferred from the form's defaultMeta
- Previously the validator's fieldApi was typed with the core FieldApi
  which has no awareness of custom meta, causing properties like
  dataSource to be typed as unknown
…' of https://github.com/wusabyRush/custom-field-meta into issue-1980-fix-custom-meta-updates-18083788771914964547

# Conflicts:
#	packages/react-form/src/useField.tsx
#	packages/react-form/tests/createFormHook.test-d.tsx
autofix-ci Bot and others added 2 commits April 29, 2026 15:20
… for same keys

Use Omit<TFormMeta, keyof TFieldMeta> & TFieldMeta instead of simple
intersection so that when both form and field define the same key (e.g.
dataSource), the field-level type takes precedence. Also apply the merged
meta type to field listeners, not just validators and render props.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant