High performance subscription-based form state management for React
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Utility functions and type helpers for enhanced TypeScript support with strongly typed form and field components.
Utility function that provides strongly typed Form and FormSpy components for specific form value types.
/**
* Creates strongly typed Form and FormSpy components for specific form values
* @returns Object with typed Form and FormSpy components
*/
function withTypes<FormValues = Record<string, any>>(): {
Form: React.ComponentType<FormProps<FormValues>>;
FormSpy: React.ComponentType<FormSpyProps<FormValues>>;
};Usage Examples:
import { withTypes } from "react-final-form";
// Define your form values interface
interface UserFormValues {
firstName: string;
lastName: string;
email: string;
age: number;
isActive: boolean;
}
// Create strongly typed components
const { Form, FormSpy } = withTypes<UserFormValues>();
// Now Form and FormSpy are fully typed for UserFormValues
function TypedUserForm() {
const onSubmit = (values: UserFormValues) => {
// values is fully typed as UserFormValues
console.log(values.firstName); // TypeScript knows this is a string
console.log(values.age); // TypeScript knows this is a number
};
return (
<Form
onSubmit={onSubmit}
initialValues={{
firstName: "John", // Type-checked
lastName: "Doe", // Type-checked
email: "john@example.com",
age: 30,
isActive: true
}}
render={({ handleSubmit, values }) => (
<form onSubmit={handleSubmit}>
{/* values is typed as UserFormValues */}
<div>Name: {values.firstName} {values.lastName}</div>
<FormSpy>
{({ values: spyValues }) => (
<div>
{/* spyValues is also typed as UserFormValues */}
Email: {spyValues.email}
Age: {spyValues.age}
</div>
)}
</FormSpy>
<button type="submit">Submit</button>
</form>
)}
/>
);
}Access to the current version of react-final-form.
/**
* Current version of react-final-form
*/
const version: string;Usage Example:
import { version } from "react-final-form";
function VersionInfo() {
return <div>React Final Form version: {version}</div>;
}Complete type definitions for all components, hooks, and interfaces.
/**
* Core form component type
*/
type FormComponent<FormValues = Record<string, any>> = React.ComponentType<
FormProps<FormValues>
>;
/**
* Core field component type
*/
type FieldComponent<
FieldValue = any,
T extends HTMLElement = HTMLElement,
FormValues = Record<string, any>
> = React.ComponentType<FieldProps<FieldValue, T, FormValues>>;
/**
* FormSpy component type
*/
type FormSpyComponent<FormValues = Record<string, any>> = React.ComponentType<
FormSpyProps<FormValues>
>;
/**
* Generic render prop function type
*/
type RenderFunction<T> = (props: T) => React.ReactNode;
/**
* Form render prop function type
*/
type FormRenderFunction<FormValues = Record<string, any>> = RenderFunction<
FormRenderProps<FormValues>
>;
/**
* Field render prop function type
*/
type FieldRenderFunction<
FieldValue = any,
T extends HTMLElement = HTMLElement,
FormValues = any
> = RenderFunction<FieldRenderProps<FieldValue, T, FormValues>>;
/**
* FormSpy render prop function type
*/
type FormSpyRenderFunction<FormValues = Record<string, any>> = RenderFunction<
FormSpyRenderProps<FormValues>
>;Comprehensive examples of advanced TypeScript usage with react-final-form.
Usage Examples:
import React from "react";
import { Form, Field, FormSpy, withTypes } from "react-final-form";
// Complex form values interface
interface ComplexFormValues {
personalInfo: {
firstName: string;
lastName: string;
dateOfBirth: Date;
};
contactInfo: {
email: string;
phone?: string;
address: {
street: string;
city: string;
zipCode: string;
};
};
preferences: {
newsletter: boolean;
theme: "light" | "dark";
notifications: string[];
};
}
// Create typed components
const { Form: TypedForm, FormSpy: TypedFormSpy } = withTypes<ComplexFormValues>();
// Typed field component
function TypedField<K extends keyof ComplexFormValues>({
name,
...props
}: {
name: K;
} & React.InputHTMLAttributes<HTMLInputElement>) {
return (
<Field name={name as string}>
{({ input, meta }) => (
<div>
<input {...input} {...props} />
{meta.error && meta.touched && <span>{meta.error}</span>}
</div>
)}
</Field>
);
}
// Generic field component with type inference
function GenericField<T extends HTMLElement = HTMLInputElement>({
name,
component = "input" as any,
...props
}: {
name: string;
component?: keyof JSX.IntrinsicElements | React.ComponentType<any>;
} & React.HTMLAttributes<T>) {
return (
<Field name={name} component={component} {...props} />
);
}
// Strongly typed form validation
function validateComplexForm(values: Partial<ComplexFormValues>) {
const errors: Partial<Record<keyof ComplexFormValues, any>> = {};
if (!values.personalInfo?.firstName) {
errors.personalInfo = { firstName: "Required" };
}
if (!values.contactInfo?.email) {
errors.contactInfo = { email: "Required" };
}
return errors;
}
// Complete typed form
function ComplexTypedForm() {
const onSubmit = (values: ComplexFormValues) => {
// All properties are type-safe
console.log(values.personalInfo.firstName);
console.log(values.contactInfo.email);
console.log(values.preferences.theme);
};
return (
<TypedForm
onSubmit={onSubmit}
validate={validateComplexForm}
initialValues={{
personalInfo: {
firstName: "",
lastName: "",
dateOfBirth: new Date()
},
contactInfo: {
email: "",
address: {
street: "",
city: "",
zipCode: ""
}
},
preferences: {
newsletter: false,
theme: "light",
notifications: []
}
}}
render={({ handleSubmit, values }) => (
<form onSubmit={handleSubmit}>
<TypedField name="personalInfo" placeholder="This would need proper nested handling" />
<TypedFormSpy>
{({ values: formValues }) => (
<div>
Theme: {formValues.preferences?.theme}
Newsletter: {formValues.preferences?.newsletter ? "Yes" : "No"}
</div>
)}
</TypedFormSpy>
<button type="submit">Submit</button>
</form>
)}
/>
);
}Additional type utilities for working with form state and field values.
/**
* Extract field value type from form values
*/
type FieldValueType<
FormValues,
FieldName extends keyof FormValues
> = FormValues[FieldName];
/**
* Create partial form values type for updates
*/
type PartialFormValues<FormValues> = Partial<FormValues>;
/**
* Form values with all fields optional (for initial values)
*/
type InitialFormValues<FormValues> = Partial<FormValues>;
/**
* Extract render props type for specific component
*/
type ExtractRenderProps<T> = T extends React.ComponentType<infer P>
? P extends { render?: (props: infer R) => any }
? R
: never
: never;
/**
* Type-safe field name extractor
*/
type FieldNames<FormValues> = keyof FormValues | string;
/**
* Validation error type for form values
*/
type FormErrors<FormValues> = Partial<Record<keyof FormValues, any>>;
/**
* Field validation function type
*/
type FieldValidationFunction<FieldValue, FormValues = any> = (
value: FieldValue,
allValues: FormValues,
meta?: any
) => any | Promise<any>;
/**
* Form validation function type
*/
type FormValidationFunction<FormValues> = (
values: FormValues
) => FormErrors<FormValues> | Promise<FormErrors<FormValues>>;Usage Examples:
// Using type utilities
interface UserForm {
name: string;
email: string;
age: number;
}
// Extract specific field type
type NameFieldType = FieldValueType<UserForm, "name">; // string
type AgeFieldType = FieldValueType<UserForm, "age">; // number
// Create validation functions with proper typing
const validateName: FieldValidationFunction<string, UserForm> = (
value,
allValues,
meta
) => {
if (!value) return "Name is required";
if (value.length < 2) return "Name must be at least 2 characters";
return undefined;
};
const validateUserForm: FormValidationFunction<UserForm> = (values) => {
const errors: FormErrors<UserForm> = {};
if (!values.name) errors.name = "Required";
if (!values.email) errors.email = "Required";
if (values.age < 18) errors.age = "Must be 18 or older";
return errors;
};
// Type-safe field names
const userFormFields: (keyof UserForm)[] = ["name", "email", "age"];Examples of integrating react-final-form with popular TypeScript libraries.
Usage Examples:
// Integration with Zod schema validation
import { z } from "zod";
const userSchema = z.object({
name: z.string().min(1, "Name is required"),
email: z.string().email("Invalid email"),
age: z.number().min(18, "Must be 18 or older")
});
type UserFormValues = z.infer<typeof userSchema>;
const validateWithZod = (values: UserFormValues) => {
try {
userSchema.parse(values);
return {};
} catch (error) {
if (error instanceof z.ZodError) {
return error.formErrors.fieldErrors;
}
return {};
}
};
// Integration with react-hook-form-like patterns
function createTypedForm<T>() {
return {
Form: withTypes<T>().Form,
FormSpy: withTypes<T>().FormSpy,
useFormState: () => useFormState<T>(),
useForm: () => useForm<T>()
};
}
const userFormComponents = createTypedForm<UserFormValues>();Install with Tessl CLI
npx tessl i tessl/npm-react-final-form