Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/framework/react/reference/functions/useform.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ title: useForm
# Function: useForm()

```ts
function useForm<TFormData, TFormValidator>(opts?): FormApi<TFormData, TFormValidator> & ReactFormApi<TFormData, TFormValidator>
function useForm<TFormData, TFormValidator>(opts?): ReactFormExtendedApi<TFormData, TFormValidator>
```

A custom React Hook that returns an extended instance of the `FormApi` class.
Expand All @@ -25,8 +25,8 @@ This API encapsulates all the necessary functionalities related to the form. It

## Returns

`FormApi`\<`TFormData`, `TFormValidator`\> & [`ReactFormApi`](../interfaces/reactformapi.md)\<`TFormData`, `TFormValidator`\>
[`ReactFormExtendedApi`](../type-aliases/reactformextendedapi.md)\<`TFormData`, `TFormValidator`\>

## Defined in

[useForm.tsx:57](https://github.com/TanStack/form/blob/main/packages/react-form/src/useForm.tsx#L57)
[useForm.tsx:65](https://github.com/TanStack/form/blob/main/packages/react-form/src/useForm.tsx#L65)
1 change: 1 addition & 0 deletions docs/framework/react/reference/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ title: "@tanstack/react-form"
## Type Aliases

- [FieldComponent](type-aliases/fieldcomponent.md)
- [ReactFormExtendedApi](type-aliases/reactformextendedapi.md)
- [UseField](type-aliases/usefield.md)

## Functions
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
id: ReactFormExtendedApi
title: ReactFormExtendedApi
---

# Type Alias: ReactFormExtendedApi\<TFormData, TFormValidator\>

```ts
type ReactFormExtendedApi<TFormData, TFormValidator>: FormApi<TFormData, TFormValidator> & ReactFormApi<TFormData, TFormValidator>;
```

An extended version of the `FormApi` class that includes React-specific functionalities from `ReactFormApi`

## Type Parameters

• **TFormData**

• **TFormValidator** *extends* `Validator`\<`TFormData`, `unknown`\> \| `undefined` = `undefined`

## Defined in

[useForm.tsx:55](https://github.com/TanStack/form/blob/main/packages/react-form/src/useForm.tsx#L55)
2 changes: 1 addition & 1 deletion packages/react-form/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export * from '@tanstack/form-core'

export type { ReactFormApi } from './useForm'
export type { ReactFormApi, ReactFormExtendedApi } from './useForm'
export { useForm } from './useForm'

export type { UseField, FieldComponent } from './useField'
Expand Down
18 changes: 13 additions & 5 deletions packages/react-form/src/useForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ export interface ReactFormApi<
}) => NodeType
}

/**
* An extended version of the `FormApi` class that includes React-specific functionalities from `ReactFormApi`
*/
export type ReactFormExtendedApi<
TFormData,
TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,
> = FormApi<TFormData, TFormValidator> & ReactFormApi<TFormData, TFormValidator>

/**
* A custom React Hook that returns an extended instance of the `FormApi` class.
*
Expand All @@ -61,23 +69,23 @@ export function useForm<
const [formApi] = useState(() => {
const api = new FormApi<TFormData, TFormValidator>(opts)

const extendedApi: typeof api & ReactFormApi<TFormData, TFormValidator> =
const extendedApi: ReactFormExtendedApi<TFormData, TFormValidator> =
api as never
extendedApi.Field = function APIField(props) {
return (<Field {...props} form={api} />) as never
return <Field {...props} form={api} />
}
// eslint-disable-next-line react-hooks/rules-of-hooks
extendedApi.useField = (props) => useField({ ...props, form: api })
extendedApi.useStore = (selector) => {
// eslint-disable-next-line react-hooks/rules-of-hooks
return useStore(api.store as any, selector as any) as any
return useStore(api.store, selector)
}
extendedApi.Subscribe = (props) => {
return functionalUpdate(
props.children,
// eslint-disable-next-line react-hooks/rules-of-hooks
useStore(api.store as any, props.selector as any),
) as any
useStore(api.store, props.selector),
)
}

return extendedApi
Expand Down
19 changes: 18 additions & 1 deletion packages/react-form/tests/useForm.test-d.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react'
import { assertType, it } from 'vitest'
import { useForm } from '../src/index'
import type { ReactFormExtendedApi } from '../src/useForm'

it('should type onSubmit properly', () => {
function Comp() {
Expand Down Expand Up @@ -34,3 +34,20 @@ it('should type a validator properly', () => {
})
}
})

it('should not have recursion problems and type register properly', () => {
const register = <Data,>(f: ReactFormExtendedApi<Data>) => f

function Comp() {
const form = useForm({
defaultValues: {
name: '',
title: '',
},
})

const x = register(form)

return null
}
})