Skip to content

Typed Forms Without Pain (Mapped Types + Generic Helpers)

A production-friendly pattern to type form values, errors, and validators using mapped types—no giant unions, no any.

Rajesh DhimanMarch 01, 20262 min read
On this page

What you’ll learn

  • How mapped types model values, errors, and touched consistently
  • How to write typed validators that scale
  • A pattern used across React/Next apps (framework-agnostic)

30‑second interview answer

Mapped types let you transform a form’s value type into related types like Errors<T> and Touched<T> while keeping keys in sync. This prevents bugs where you add a field but forget to update error handling. The key idea is: define the form data once, derive everything else from it.


Step 1: Define the form values type once

type SignupValues = {
  email: string;
  password: string;
  marketingOptIn: boolean;
};

type Errors<T> = {
  [K in keyof T]?: string;
};
 
type Touched<T> = {
  [K in keyof T]?: boolean;
};
 
type SignupErrors = Errors<SignupValues>;
type SignupTouched = Touched<SignupValues>;

This keeps keys aligned forever.


Step 3: Typed validators

A common validator shape:

type Validator<T> = (values: T) => Errors<T>;
 
const validateSignup: Validator<SignupValues> = (values) => {
  const errors: Errors<SignupValues> = {};
 
  if (!values.email.includes("@")) errors.email = "Invalid email";
  if (values.password.length < 8) errors.password = "Min 8 characters";
 
  return errors;
};

No casts, no stringly-typed keys.


Step 4: Field-level validators with key-safe access

type FieldValidator<T, K extends keyof T> = (value: T[K], values: T) => string | undefined;
 
type FieldValidators<T> = {
  [K in keyof T]?: FieldValidator<T, K>;
};
 
const fieldValidators: FieldValidators<SignupValues> = {
  email: (email) => (email.includes("@") ? undefined : "Invalid email"),
  password: (pw) => (pw.length >= 8 ? undefined : "Too short")
};

Now the validator signature always matches the field type.


Common mistakes

  • Storing errors as Record<string, string> (loses key safety)
  • Copy-pasting field names into multiple types (guaranteed drift)
  • Over-modeling nested forms before you need it

Production rule of thumb

  • Define Values once.
  • Derive Errors<T>, Touched<T>, validators, and field configs from it.
  • Prefer small, composable validators.

Interview questions

  1. Q: What do mapped types buy you in forms?

    • A: Key-level consistency: add/remove fields once and all derived types update.
  2. Q: How do you type a validator for a specific field?

    • A: Use generics like FieldValidator<T, K> and map it across keys.

Quick recap

  • Mapped types keep form keys consistent.
  • Typed validators scale without string keys.
  • This is high-signal TypeScript that’s actually practical.
Companion Book

Looking for structured, offline interview prep?

Free online lessons • Portable Amazon Kindle / Paperback

Frontend Interview Guide (2025 Edition) cover
Recommended for React & Frontend Rounds

Frontend Interview Guide (2025 Edition)

By Rajesh Dhiman

Comprehensive preparation covering React internals, Web Performance, CSS architecture, and system design questions.

View on Amazon ↗Kindle & Paperback
JavaScript Interview Guide cover
Recommended for Core JS Rounds

JavaScript Interview Guide

By Rajesh Dhiman

Deep dive into the Event Loop, microtask draining, closures, prototypal inheritance, and asynchronous execution patterns.

View on Amazon ↗Kindle & Paperback

Note: All lessons on Frontend Interview remain completely free to read online. As an Amazon Associate, we may earn from qualifying purchases.

RD

Written by Rajesh Dhiman

Authored by Rajesh Dhiman and engineered at Eunix Tech. Focused on deep-dive frontend engineering, JavaScript runtime internals, React architecture, and web performance.