Angular 20.2 – What’s New in the Latest Release

A fresh Angular update is out, packed with several notable additions. Below is a breakdown of the key improvements.

Zoneless Angular graduates from developer preview to stable.

After a lengthy wait, this milestone has arrived. In Angular 20.2, Zoneless is officially stable and ready for production use. That said, this article focuses on the recent modifications; Zoneless itself is a deep topic. For a thorough explainer, check out this detailed guide.

Full support for TypeScript 5.9.

The newest Angular release now fully supports TypeScript 5.9, unlocking access to a range of modern language capabilities that can boost both runtime efficiency and the developer experience.

For instance, you can now import a module lazily without immediate execution:

import defer * as myFeature from "./common-module.js"
//no side effect//

//Here code is executed//
const value = myFeature.count();

TypeScript 5.9 also brings a subtle yet valuable enhancement: editor tooltips and hover hints now display complete interface types. This eliminates the need to jump between definitions, making complex types far easier to grasp. The visual difference is shown below:

Angular 20.2 – the recent changes — figure 1

Further details on this TypeScript release are available here.

Enhanced redirected property support.

Firstly, this change lets you inject your own logic based on whether a request was redirected. Consider the following example:

export class RedirectServiceExample {
  private readonly _httpClient = inject(HttpClient);
  private readonly _userHandler = inject(UserHandler);
 
  getUser(Id: string) {
    return this._httpClient.get(`/api/users/${Id}`, { observe: 'response'     }).pipe(
      map((response: HttpResponse<any>) => {
        if (response.redirected) 
          return this._userHandler.processRedirectedUser(id)
        else return this._userHandler.processUser(response.body)
      })
    );
  }

The logic is conditionally appended, granting precise control over request handling in redirect scenarios. Depending on the redirect status, you can apply distinct strategies—such as logging redirects for analytics, enforcing extra security measures, or altering the application flow.

Secondly, this aligns HttpClient more closely with the native Fetch API. By surfacing the redirected property, the client now offers a familiar and consistent interface for developers.

Moreover, this feature strengthens application security. You can, for example, block unauthorized redirects or introduce additional verification steps when one is detected—particularly useful for cross-origin policy enforcement.

The redirected property also aids analytics, letting you track how frequently and under what conditions redirects occur. This data helps evaluate the performance, stability, and architectural compliance of your request pipeline.

Looking to stay current with Angular’s evolution? Our free ebook spans everything from Angular 14 to the latest version: features, use cases, and business impact. It’s a comprehensive, practical reference. Download it here.

Angular 20.2 – the recent changes — figure 2

New animation API.

The revised animation API eliminates the need to import the animations module, which carries significant weight. Firstly, this can shrink the final bundle size. Secondly, it simplifies animation handling using plain style files instead of Angular-specific libraries. Another key addition is the enter and leave functionality, enabling you to animate HTML elements without importing the animations module. This approach also lowers the barrier for newcomers to Angular animations. Here’s how it works with the latest update:

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrl: './app.component.scss'
})
export class AppComponent {
  private readonly _menuOpen = signal(false);
  protected readonly isMenuOpen = computed(() => this._menuOpen());


  protected toggleMenu() {
    this._menuOpen.update(value => !value);
  }


  protected closeMenu() {
    this._menuOpen.set(false);
  }
}

HTML file:

<button (click)="toggleMenu()">Toggle Menu</button>


@if (isMenuOpen()) {
  <div
    animate.enter="animate-in"
    animate.leave="animate-out"
    (click)="closeMenu()"
  >
    <!-- Your content -->
    <p>Click to close</p>
  </div>
}

And finally, part of our styles:

@keyframes animate-in {
  from {
    transform: translateY(50%);
  }
  to {
    transform: translateY(0);
  }
}


.animate-in {
  animation: animate-in 0.35s ease-in-out;
}


@keyframes animate-out {
  from {
    transform: translateY(0);
  }
  to {
    transform: translateY(50%);
  }
}


.animate-out {
  animation: animate-out 0.35s ease-in-out;
}

In my view, this is a clear win for developer experience. Compare it with the previous approach using animation modules:

<h2>Old Angular Animations</h2>
<button (click)="toggleMenu()">Toggle Menu</button>


@if (isMenuOpen()) {
  <div
    @menu
    (click)="closeMenu()"
  >
    <p>Click to close</p>
  </div>
}
@Component({
 /…/,
 animations: [
    trigger('menu', [
      transition(':enter', [
        style({ transform: 'translateY(120%)' }),
        animate('0.35s ease-in-out', style({ transform: 'translateY(0)' }))
      ]),
      transition(':leave', [
        animate('0.35s ease-in-out', style({ transform: 'translateY(120%)' }))
      ])
    ])
})
export class AppComponent {
  private readonly _menuOpen = signal(false);
  protected readonly isMenuOpen = computed(() => this._menuOpen());


  protected toggleMenu() {
    this._menuOpen.update(value => !value);
  }


  protected closeMenu() {
    this._menuOpen.set(false);
  }
}

Setting aside the inline styles, the new functionality is noticeably more ergonomic. Additionally, these changes may lead to performance improvements for applications running on devices like mobile phones. Some library animations rely on the CPU rather than the GPU, which can hamper performance; the new approach mitigates this.

Expanded @else if capabilities.

With Angular 20.2, you can use the as keyword to extract object fields directly within your HTML template and use them in conditions. This now extends to the @else if block. It’s remarkably straightforward:

@Component({
 //…//
 template: `
    @if(user(); as user) {
      <p>{{user.name}}</p>
    } @else if(admin(); as admin) {
      <p>Hi admin {{admin.nickName}} </p>
    }
 `,
})
export class App {
  //…//
})

In this basic example, you read the user’s type and, thanks to type narrowing, conditionally render different content in the template.

Extended diagnostic for uninvoked functions.

Prior to Angular 20.2, there was no check for functions used within text interpolation without invocation. Signals already had a warning mechanism for this:

@Component({
 template: `
   {{text}}
 `,
})
export class App {
 protected readonly text = signal<string>('Hello angular 20.2');
}

In such cases, the following warning is shown:

[WARNING] NG8109: text is a function and should be invoked: text() [plugin angular-compiler]

Since Angular 20.2, a similar error appears when a function is not invoked:

@Component({
  //…//
  template: `
    {{text}}
 `,
})
export class App {
  protected text(): string {
   return ‘Hello Angular 20.2’;
  }
}

That said, I trust you avoid directly invoking functions in templates. This is a well-known anti-pattern that can trigger unnecessary change detection cycles and degrade performance. Prefer using getters or pre-computed properties in your component class instead.

Replacing getCurrentNavigation method.

Starting with Angular 20.2, reactivity has grown slightly. You can now call currentNavigation() from your Router instance and compute it, rather than using the getCurrentNavigation method, which returns a Navigation object or null. currentNavigation is a signal, allowing you to derive its state. Please note that getCurrentNavigation is now deprecated as of this update.

@Component({
  //…//
})
export class App {
  private readonly _router = inject(Router);
  protected readonly navigated = computed(() =>
    this._router.currentNavigation()
  );
}

Modified FormArray API.

The FormArray API has seen changes in Angular 20.2. Previously, pushing an array of controls into a FormArray required iterating over the array and pushing each control individually:

export class App implements OnInit {
 protected formArray = new FormArray<FormControl<string | null>>([]);
 private readonly _controls = [
   new FormControl({ value: '', disabled: false }),
   new FormControl({ value: 'Name', disabled: false }),
 ];


 ngOnInit() {
   // before Angular 20.2 release
   this._controls.forEach((control) => {
     this.formArray.push(control);
   })
 }

Now, you can push controls in a single call:

 ngOnInit() {
   // after Angular 20.2 release
   this.formArray.push(this._controls);
 }

With the iteration approach, each push triggers a separate event. The new method fires only one event after all controls are added, resulting in better Angular performance.

Exposed referrer and integrity for httpResource.

With each release (see the Angular 20.1 article), httpResource has been steadily enhanced. The latest version adds the referrer and integrity options. Let’s clarify why these are useful. The referrer option lets you specify or hide the source page making an external HTTP request. The integrity option allows verification that a resource hasn’t been tampered with—crucial for application security. Here’s a simple example:

@Component({
  //…//
})
export class App {
   protected readonly resource = httpResource(() => ({
   //rest of settings//
   referrer: 'no-referrer',
   integrity: 'your_sha_key',
 }));
};

Allowed binding to aria attributes.

Since this Angular version, you can bind ARIA attributes directly, without the attr. prefix. This change simplifies developer workflow and, more importantly, improves server-side rendering. See the example below:

@Component({
 //…//
 template: `
   <button [ariaLabel]=”label”>Click me</button> //New way
   <button [attr.aria.label]=”label”>Click me</button> //Old way
 `,
})
export class App {
 protected readonly label = `New aria property binding`;
}

Summary

I recommend considering an upgrade to Angular 20.2 for your project. The recent changes bring notable improvements to both application performance and developer experience. For a recap of the previous release, I invite you to read this article: