Typed Reactive Forms (v14)
📚 What are Typed Forms?
Typed Reactive Forms were introduced in Angular 14 for better type safety:
- Type inference: Form values are typed, not 'any'
- Compile-time errors: Catch typos and type mismatches
- IDE support: Autocomplete for form controls
- NonNullableFormBuilder: Controls that reset to initial value
🎯 Interview Questions
- Q1: What is the difference between typed and untyped forms?
- A: Typed forms have strict typing on .value, providing autocomplete and compile-time type checking. Untyped forms return 'any'.
- Q2: What is NonNullableFormBuilder?
- A: A form builder that creates controls with nonNullable: true by default. On reset(), they return to initial value instead of null.
- Q3: How do you get the raw value vs value of a form?
- A: .value excludes disabled controls. .getRawValue() includes all controls including disabled ones.
- Q4: What is the difference between FormControl<string> and FormControl<string | null>?
- A: FormControl<string> (nonNullable) can never be null. FormControl<string | null> can be reset to null.
🔧 Live Demo - Typed Form
Form State:
Valid: false
Dirty: false
Touched: false
Form Value (Typed!):
{
"name": "",
"email": "",
"age": null,
"address": {
"street": "",
"city": "",
"zipCode": ""
}
}💻 Typed Forms Code
import { FormControl, FormGroup, Validators } from '@angular/forms';
// Define interfaces for type safety
interface UserForm {
name: FormControl<string>;
email: FormControl<string>;
age: FormControl<number | null>;
}
// Create typed form
userForm = new FormGroup<UserForm>({
// nonNullable: true - resets to initial value, not null
name: new FormControl('', {
nonNullable: true,
validators: [Validators.required]
}),
email: new FormControl('', {
nonNullable: true,
validators: [Validators.email]
}),
age: new FormControl<number | null>(null), // Can be null
});
// Type-safe access!
const name: string = this.userForm.controls.name.value; // ✅ Typed!
const email = this.userForm.value.email; // string | undefined
// Using NonNullableFormBuilder (shorthand)
import { NonNullableFormBuilder, inject } from '@angular/core';
class MyComponent {
private fb = inject(NonNullableFormBuilder);
form = this.fb.group({
name: ['', Validators.required],
email: ['', Validators.email],
});
// All controls are nonNullable by default!
}
// getRawValue() includes disabled controls
const rawValue = this.userForm.getRawValue();