CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-final-form

High performance subscription-based form state management for React

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

typescript.mddocs/

TypeScript Support

Utility functions and type helpers for enhanced TypeScript support with strongly typed form and field components.

Capabilities

withTypes Utility

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>
      )}
    />
  );
}

Version Information

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>;
}

TypeScript Type Definitions

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>
>;

Advanced TypeScript Patterns

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>
      )}
    />
  );
}

Type Utilities and Helpers

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"];

Integration with External Type Systems

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

docs

field.md

form-spy.md

form.md

hooks.md

index.md

typescript.md

tile.json