← Back to Articles         
What Are Typed Reactive Forms in Angular?

What Are Typed Reactive Forms in Angular?

Published on 01 Oct 2026     7 min read Angular
Angular forms

What Are Typed Reactive Forms in Angular?

1. What Are Typed Reactive Forms?

Typed Reactive Forms are Angular Reactive Forms where TypeScript knows the exact data type of each form control.

For example:

name: FormControl<string>
age: FormControl<number>
isActive: FormControl<boolean>

Because Angular knows these types, TypeScript can detect incorrect assignments at compile time.

FormControl<string>
        ↓
Only string values

FormControl<number>
        ↓
Only number values

Typed Reactive Forms make forms type-safe and reduce runtime mistakes.


2. Full Simple Sample Program

app.ts

import { Component } from '@angular/core';
import {
  FormControl,
  FormGroup,
  ReactiveFormsModule,
  Validators
} from '@angular/forms';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [ReactiveFormsModule],
  templateUrl: './app.html'
})
export class App {

  employeeForm = new FormGroup({

    name: new FormControl('', {
      nonNullable: true,
      validators: [Validators.required]
    }),

    age: new FormControl(0, {
      nonNullable: true,
      validators: [Validators.required, Validators.min(18)]
    }),

    email: new FormControl('', {
      nonNullable: true,
      validators: [Validators.required, Validators.email]
    }),

    isActive: new FormControl(true, {
      nonNullable: true
    })

  });

  submitForm() {

    if (this.employeeForm.valid) {

      const employee = this.employeeForm.getRawValue();

      console.log(employee);

      console.log(employee.name);
      console.log(employee.age);
      console.log(employee.email);
      console.log(employee.isActive);

    } else {

      this.employeeForm.markAllAsTouched();

    }
  }
}

app.html

<h2>Employee Form</h2>

<form
  [formGroup]="employeeForm"
  (ngSubmit)="submitForm()">

  <div>
    <label>Name:</label>

    <input
      type="text"
      formControlName="name">

    @if (
      employeeForm.controls.name.touched &&
      employeeForm.controls.name.hasError('required')
    ) {
      <p>Name is required.</p>
    }
  </div>

  <br>

  <div>
    <label>Age:</label>

    <input
      type="number"
      formControlName="age">

    @if (
      employeeForm.controls.age.touched &&
      employeeForm.controls.age.hasError('min')
    ) {
      <p>Age must be at least 18.</p>
    }
  </div>

  <br>

  <div>
    <label>Email:</label>

    <input
      type="email"
      formControlName="email">

    @if (
      employeeForm.controls.email.touched &&
      employeeForm.controls.email.hasError('email')
    ) {
      <p>Please enter a valid email.</p>
    }
  </div>

  <br>

  <div>
    <label>
      <input
        type="checkbox"
        formControlName="isActive">

      Active
    </label>
  </div>

  <br>

  <button type="submit">
    Submit
  </button>

</form>

3. How Is This Form Typed?

Consider:

name: new FormControl('', {
  nonNullable: true
})

The initial value is:

''

which is a string.

Angular/TypeScript therefore infers:

FormControl<string>

Similarly:

age: new FormControl(0, {
  nonNullable: true
})

becomes:

FormControl<number>

and:

isActive: new FormControl(true, {
  nonNullable: true
})

becomes:

FormControl<boolean>

So conceptually:

employeeForm
│
├── name
│     └── FormControl<string>
│
├── age
│     └── FormControl<number>
│
├── email
│     └── FormControl<string>
│
└── isActive
      └── FormControl<boolean>

4. Why Do We Need Typed Reactive Forms?

Suppose age should contain a number.

With typed forms:

this.employeeForm.controls.age.setValue(25);

This is valid.

But:

this.employeeForm.controls.age.setValue('Twenty Five');

TypeScript reports a compile-time error because:

Expected:

number

Received:

string

This catches mistakes while developing the application rather than waiting for runtime.


5. Type Inference

You don't always have to explicitly write:

FormControl<string>

Angular can infer it.

For example:

const name = new FormControl('Syed');

TypeScript understands the control's type based on the initial value.

However, there is an important detail:

const name = new FormControl('Syed');

is normally:

FormControl<string | null>

rather than simply:

FormControl<string>

Why?

Because Angular allows:

name.reset();

and a nullable control normally resets to:

null

6. Typed Forms and null

This is one of the most important concepts in Typed Reactive Forms.

Consider:

const name = new FormControl('Syed');

Its type is generally:

FormControl<string | null>

Therefore:

name.value

can be:

"Syed"

or

null

7. Using nonNullable

If you don't want null, use:

const name = new FormControl('Syed', {
  nonNullable: true
});

Now its type is:

FormControl<string>

instead of:

FormControl<string | null>

This also affects reset behavior.

Nullable

const name = new FormControl('Syed');

name.reset();

Value becomes:

null

Non-nullable

const name = new FormControl('Syed', {
  nonNullable: true
});

name.reset();

Value returns to:

Syed

the initial value.


8. Typed FormGroup

You can also explicitly declare the type of the complete form.

interface EmployeeForm {
  name: FormControl<string>;
  age: FormControl<number>;
  email: FormControl<string>;
  isActive: FormControl<boolean>;
}

Then:

employeeForm = new FormGroup<EmployeeForm>({
  name: new FormControl('', {
    nonNullable: true
  }),

  age: new FormControl(0, {
    nonNullable: true
  }),

  email: new FormControl('', {
    nonNullable: true
  }),

  isActive: new FormControl(true, {
    nonNullable: true
  })
});

Now the entire form structure is strongly typed.

FormGroup<EmployeeForm>
        │
        ├── FormControl<string>
        ├── FormControl<number>
        ├── FormControl<string>
        └── FormControl<boolean>

9. Typed Forms with NonNullableFormBuilder

For many forms, a convenient modern approach is using:

NonNullableFormBuilder

Instead of repeatedly writing:

{
  nonNullable: true
}

we can use the builder.

Example

import { Component, inject } from '@angular/core';
import {
  NonNullableFormBuilder,
  ReactiveFormsModule,
  Validators
} from '@angular/forms';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [ReactiveFormsModule],
  templateUrl: './app.html'
})
export class App {

  private fb = inject(NonNullableFormBuilder);

  employeeForm = this.fb.group({

    name: ['', Validators.required],

    age: [0, [
      Validators.required,
      Validators.min(18)
    ]],

    email: ['', [
      Validators.required,
      Validators.email
    ]],

    isActive: [true]

  });

  submitForm() {

    const employee = this.employeeForm.getRawValue();

    console.log(employee);
  }
}

Angular infers:

name      → string
age       → number
email     → string
isActive  → boolean

This avoids a lot of:

string | null
number | null
boolean | null

handling.


10. Typed FormArray

FormArray can also be typed.

For example, a list of skills:

skills = new FormArray<FormControl<string>>([
  new FormControl('C#', {
    nonNullable: true
  }),
  new FormControl('Angular', {
    nonNullable: true
  })
]);

Now every item must be:

FormControl<string>

This is valid:

this.skills.push(
  new FormControl('SQL', {
    nonNullable: true
  })
);

The type system prevents incompatible controls from being added.


11. Typed vs Untyped Reactive Forms

Angular also has legacy untyped APIs such as:

UntypedFormControl
UntypedFormGroup
UntypedFormArray
UntypedFormBuilder

The conceptual difference is:

Typed Forms Untyped Forms
FormControl<string> UntypedFormControl
Compile-time type checking Much less type checking
Better IntelliSense Less precise IntelliSense
Safer refactoring More runtime risk
Modern/default approach Mainly migration/legacy use cases

For new applications, typed reactive forms are generally the appropriate default.


12. Typed Forms Do Not Mean Validation

This is an important interview distinction.

Typing:

FormControl<number>

means:

The control's value should have the TypeScript type number.

Validation:

Validators.min(18)

means:

The number must be at least 18.

These solve different problems.

Type Safety
    ↓
FormControl<number>
    ↓
Must be a number


Validation
    ↓
Validators.min(18)
    ↓
Must be >= 18

You often use both together:

age: new FormControl(0, {
  nonNullable: true,
  validators: [
    Validators.required,
    Validators.min(18)
  ]
})

13. Advantages

Typed Reactive Forms provide:

  • Compile-time type safety
  • Better IDE IntelliSense
  • Earlier detection of programming mistakes
  • Safer setValue() and patchValue() usage
  • Safer form refactoring
  • Strongly typed form values
  • Better maintainability for large applications
  • Strong integration with TypeScript's type system

14. Key Points

  • Typed Reactive Forms provide type-safe Angular forms.
  • Angular's standard reactive form APIs support typing.
  • FormControl<string> represents a string control.
  • FormControl<number> represents a numeric control.
  • FormGroup can have a strongly typed control structure.
  • FormArray can also be strongly typed.
  • Angular can infer many control types from initial values.
  • Normal FormControl values often include null.
  • nonNullable: true removes null from the control's value type and changes reset behavior.
  • NonNullableFormBuilder makes non-nullable typed forms more convenient.
  • Type safety and validation are different concepts.
  • Typed forms catch many programming mistakes during development.

15. Interview Questions and Answers

1. What are Typed Reactive Forms?

Typed Reactive Forms are Angular Reactive Forms that use TypeScript types for form controls, groups, arrays, and their values, providing compile-time type safety.


2. Give an example of a typed control.

const name = new FormControl<string>('', {
  nonNullable: true
});

Here name is:

FormControl<string>

3. What is the advantage of typed forms?

They provide compile-time checking and better IntelliSense.

For example, a FormControl<number> prevents accidentally assigning a string through the typed API.


4. Why does FormControl('Syed') normally include null?

Because a normal control can be reset:

control.reset();

and its value can become null.

Therefore its inferred type is typically:

FormControl<string | null>

5. What does nonNullable: true do?

It creates a non-nullable control:

FormControl<string>

instead of:

FormControl<string | null>

It also causes reset() to restore the initial value rather than resetting to null.


6. What is NonNullableFormBuilder?

It is a convenient FormBuilder variant that creates non-nullable controls by default.

private fb = inject(NonNullableFormBuilder);

7. Are Typed Reactive Forms the same as validation?

No.

Typing
    ↓
What type of value?

string / number / boolean


Validation
    ↓
Is that value acceptable?

required / min / max / email

For example:

FormControl<number>

provides type safety, while:

Validators.min(18)

provides runtime form validation.


Interview Summary

Typed Reactive Forms provide compile-time type safety for Angular forms. Controls can have explicit or inferred types such as FormControl<string> or FormControl<number>. This improves IntelliSense, catches type errors during development, and makes form code safer to maintain. Since normal controls may contain null, nonNullable: true or NonNullableFormBuilder can be used when null values are not desired.

← Back to Articles