Graneet Form LogoGraneet form

Complex TypeScript

Advanced TypeScript patterns and usage for graneet-form at scale

Complex TypeScript

At Graneet, we use the library with complex patterns in production. This section showcases advanced TypeScript features and patterns used in real applications.

Template Literal Types

This example demonstrates how to use template literal types with graneet-form to create dynamic, type-safe field names. This pattern is particularly useful when you need to generate multiple fields programmatically while maintaining full TypeScript support.

Loading...

Key Features

  • Template Literal Types: Dynamic field names with firstName-${number} pattern
  • Type Guards: Runtime type checking with compile-time type narrowing
  • Dynamic Field Generation: Programmatically create multiple form fields
  • Full Type Safety: TypeScript ensures you can only access valid field names

Code Breakdown

Template Literal Type Definition

type FieldName = `firstName-${number}`;

interface FormValues {
  [firstNameField: FieldName]: string;
  otherField: number;
}

This creates a type that accepts any string matching the pattern firstName-{number}, such as firstName-0, firstName-1, etc.

Field Name Generator

const getFieldName = (index: number): FieldName => {
  return `firstName-${index}`;
};

A helper function that generates valid field names with proper typing.

Type Guard Function

const isFirstName = (fieldName: string): fieldName is FieldName => {
  return fieldName.split('-')[0] === 'firstName';
};

This function provides both runtime validation and compile-time type narrowing. When used in an if statement, TypeScript knows that the field is of type FieldName.

Usage in Form Processing

const onClick = () => {
  const formValues = form.getFormValues();
  const values: string[] = [];

  Object.keys(formValues).forEach((key) => {
    if (isFirstName(key)) {
      // TypeScript knows formValues[key] is a string here
      values.push(formValues[key]);
    }
  });

  alert(`First names: ${values.join(', ')}`);
};

The type guard ensures that only fields matching the firstName-${number} pattern are processed, and TypeScript provides full autocomplete and type checking.

Production Tip: This pattern is excellent for forms with dynamic sections, such as adding/removing items in a list, where each item has multiple fields that need to be tracked individually.

When to Use This Pattern

  • Dynamic Forms: When the number of fields changes based on user interaction
  • Repeating Sections: Forms with add/remove functionality for similar field groups
  • Complex Data Structures: When working with arrays or nested objects in forms
  • Type Safety: When you need compile-time guarantees about field access

This approach combines the flexibility of dynamic forms with the safety and developer experience of TypeScript's advanced type system.