Form TypeScript Integration#
Ant Design's Form component provides first-class TypeScript support through a generic Values type parameter that flows from the form instance down to all methods for field access, mutation, and validation. The two primary entry points are Form.useForm<Values>() (hooks-based) and useRef<FormInstance<Values>>() (ref-based). NamePath — the union type string | number | (string | number)[] — is used throughout the API to address both flat and nested fields.
FormInstance<Values> and useForm<Values>()#
useForm<Values>() is the standard way to create a typed form instance in functional components:
const [form] = Form.useForm<FormValues>();
The hook returns a single-element tuple [FormInstance<Values>] . The antd FormInstance<Values> extends @rc-component/form's RcFormInstance<Values> and adds:
scrollToField(name: NamePath, options?: ScrollOptions): voidfocusField(name: NamePath): voidgetFieldInstance(name: NamePath): any
For class components or imperative access, use a ref typed as useRef<FormInstance<FormValues>>(null). The type test suite demonstrates both patterns .
FormProps<Values> also accepts a typed form prop so the component itself carries the generic through rendering:
<Form<FormValues> form={form} onFinish={(values) => { /* values: FormValues */ }} />
The component's public export re-exports FormInstance, useForm, useWatch, and List for consumers .
NamePath Type System#
NamePath is re-exported from @rc-component/form and defined as:
type NamePath = string | number | (string | number)[]
This single union covers three addressing styles :
| Style | Example | Use case |
|---|---|---|
| String | "username" | Top-level field |
| Number | 0 | Array index |
| Array | ['user', 'address', 'street'] or [field.name, 'age'] | Nested / Form.List fields |
When a name array contains a number and no matching key exists in the store, the store automatically converts that segment to an array; use string indices ('0') to keep object semantics .
InternalNamePath (always an array) is the normalized form used internally and is available as a separate export from interface.ts for advanced scenarios.
Type Propagation to Form Methods#
All FormInstance methods accept NamePath parameters :
| Method | Signature (simplified) |
|---|---|
getFieldValue | (name: NamePath) => any |
getFieldError | (name: NamePath) => string[] |
setFieldValue | (name: NamePath, value: any) => void |
setFieldsValue | (values: Partial<Values>) => void |
validateFields | (nameList?: NamePath[], config?: ValidateConfig) => Promise<Values> |
resetFields | (fields?: NamePath[]) => void |
scrollToField | (name: NamePath, options?: ScrollOptions) => void |
The Values generic on FormInstance<Values> types the argument to setFieldsValue and the resolved value of validateFields/onFinish. The type test verifies this end-to-end:
form.setFieldsValue({ path1: { path2: 2333 } }); // typed to FormValues
getFieldsValue is overloaded: called with no arguments it returns registered fields; called with true it returns all store values (including unregistered); called with a nested NamePath[][] it returns values at those paths .
Form.Item Generic and useWatch#
Form.Item<Values> also accepts the same Values generic, enabling typed render props:
<Form.Item<FormValues>>
{({ getFieldsValue }) => {
const values = getFieldsValue(); // typed as FormValues
}}
</Form.Item>
Form.useWatch accepts a NamePath or a selector function and optionally takes FormInstance as a second argument to watch a specific instance . The return type infers from the selector when a function is provided (5.12.0+).
Key Source Files#
| File | Purpose |
|---|---|
components/form/interface.ts | Re-exports NamePath, InternalNamePath, Store, StoreValue from @rc-component/form |
components/form/hooks/useForm.ts | Defines FormInstance<Values> and useForm<Values>() |
components/form/Form.tsx | Defines FormProps<Values>, wires the generic through the component |
components/form/__tests__/type.test.tsx | Type-level tests covering hooks, refs, render props, and useWatch |