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.
F
Frontend Interview Team
March 01, 2026
What you’ll learn
- How mapped types model
values,errors, andtouchedconsistently - 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;
};Step 2: Derive related structures via mapped types
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
Valuesonce. - Derive
Errors<T>,Touched<T>, validators, and field configs from it. - Prefer small, composable validators.
Interview questions
-
Q: What do mapped types buy you in forms?
- A: Key-level consistency: add/remove fields once and all derived types update.
-
Q: How do you type a validator for a specific field?
- A: Use generics like
FieldValidator<T, K>and map it across keys.
- A: Use generics like
Quick recap
- Mapped types keep form keys consistent.
- Typed validators scale without string keys.
- This is high-signal TypeScript that’s actually practical.