Main topics: TypeScript 6.0 and NgRx (RFCs for delegatedSignal and resource extensions). Also in brief: Martina Kraus on security, debounce for async validators, Alfredo Perez on SpecKit, and Angular Graz on YouTube.

TypeScript 6.0

The recent release of TypeScript 6.0 marks the final version of the compiler that remains authored in TypeScript itself. Officially, this iteration is positioned as the transitional layer between TypeScript 5 and the upcoming TypeScript 7, which is slated to be rewritten in Go. It's important to note that TypeScript 6 is not yet integrated into Angular. Consequently, developers cannot leverage its changes immediately. While Angular 21 aligns with TypeScript 5.9, support for TypeScript 6 is anticipated in Angular 22.

To pave the way for version 7, TypeScript 6 focuses heavily on deprecations and adjusted default settings that reflect the current state of the TypeScript ecosystem.

For instance, ESM now serves as the default module system, strict mode is enabled by default, and the compilation target defaults to the ECMAScript version corresponding to the last year's edition, which is ECMAScript 2025 at this time.

Among the deprecations is the ES5 target, which was the last JavaScript version lacking class syntax, lambda expressions, Promises, `let` or `const`, string interpolation, and numerous other modern features. Additionally, the `baseUrl` property in the `tsconfig.json` file has been removed, and support for the amd, umd, and systemjs module formats has been discontinued. While these deprecations can be circumvented, this is only a temporary reprieve, as TypeScript 7 will enforce these removals.

An experimental automatic migration tool is being provided to assist with this transition.

Announcing TypeScript 6.0 - TypeScript

TypeScript 6.0 is now available! TypeScript 6 is a stepping-stone release, aligning with the upcoming native-speed 7.0 release.

favicon devblogs.microsoft.com

There are also new features, with the most notable being the inclusion of the Temporal API.

This is a new, built-in date and time API for JavaScript, positioned as a comprehensive replacement for the legacy Date object. It offers significantly more functionality, including timezone handling, support for alternative calendar systems like the Chinese calendar, immutable operations, and a broad set of utility methods.

Long-time developers may draw a parallel to the migration to the Date-Time API in Java over a decade ago, which served a similar purpose.

The Temporal API has achieved stage 4 of the TC39 process, signifying its standardization and completion. However, this does not guarantee universal platform support. While the latest versions of Chrome and Firefox have implemented it, Safari and Node.js have not. Therefore, developers intending to use it should ensure their code is safeguarded with polyfills.


const today = Temporal.Now.plainDateISO();
const startOfYear = today.with({ month: 1, day: 1 });
const diff = startOfYear.until(today);

console.log(`${diff.days} days have passed`);
Enter fullscreen mode Exit fullscreen mode

NgRx RFCs

NgRx, the leading state management library for Angular, has officially begun the groundwork for supporting resources and forms. Two RFCs have been published to this end.

delegatedSignal()

The first RFC, aimed at supporting Signal Forms, introduces a new Signal type named delegatedSignal. From the outside, it presents itself as a writable Signal, yet it does not hold a value itself. Instead, it reads and writes to another Signal. What is the purpose of this?

Consider a user object stored in a Signal, containing two nested properties: name and address. name includes firstName and lastName, while address contains street and city.

const user = signal({
  name: { firstName: 'John', lastName: 'Doe' },
  address: { street: '123 Main St', city: 'Anytown' }
});
Enter fullscreen mode Exit fullscreen mode

If a form requires a flattened representation of this user object, a linkedSignal would typically be employed. The challenge arises when modifications within the form need to be reflected back to the original Signal. Currently, the only solution is to use an effect.

@Component({
  template: ``
})
export class UserPage {
  user = signal({
    name: {
      firstname: "John",
      lastname: "Doe"
    },
    address: {
      street: 'Main Street',
      city: 'London'
    }
  })

  userFormModel = linkedSignal(() => ({
    firstname: this.user().name.firstname,
    lastname: this.user().name.lastname,
    city: this.user().address.city,
    street: this.user().address.street,
  }))

  userForm = form(this.userFormModel);

  syncEffect = effect(() => {
    const { firstname, lastname, street, city } = this.userFormModel();

    this.user.set({
      name: { firstname, lastname },
      address: { street, city }
    })
  })
}
Enter fullscreen mode Exit fullscreen mode

delegatedSignal offers a solution by synchronously writing changes back to the originating Signal.

// PROTOTYPE!!!
export function delegatedSignal<T>(config: {
  computation: () => T,
  update: (value: T) => void
}
): WritableSignal<T> {
  const delegated = linkedSignal(config.computation);

  delegated.set = (value: T) => config.update(value);
  delegated.update = (updateFn: (value: T) => T) => updateFn(delegated())

  return delegated;
}


@Component({
  template: ``
})
export class UserPage {
  user = signal({
    name: {
      firstname: "John",
      lastname: "Doe"
    },
    address: {
      street: 'Main Street',
      city: 'London'
    }
  })

  userFormModel = delegatedSignal({
    computation: () => {
      const { 
        name: { firstname, lastname }, 
        address: { city, street } 
      } = this.user();
      return { firstname, lastname, street, city }
    },
    update: ({ firstname, lastname, street, city }) => {
      this.user.set({
        name: { firstname, lastname },
        address: { street, city }
      })

    }
  })

  userForm = form(this.userFormModel);
}

Enter fullscreen mode Exit fullscreen mode

The utility of delegatedSignal extends beyond just forms. For example, in the context of a SignalStore, one could link a Signal Form directly to the SignalStore, ensuring that any form mutation is instantly persisted to the store.

Think of delegatedSignal as a linkedSignal that forgoes creating a clone and instead writes directly to the original Signal. A variant of delegatedSignal, known as deepSignal, already exists within the Angular framework, though it is not part of the public API. Angular uses it internally for its Signal Forms implementation.
https://github.com/angular/angular/blob/394ad0c2a26eec8a8f7136b1b7971420b30a117e/packages/forms/signals/src/util/deep_signal.ts#L21

ngrx/platform#5121 — RFC delegatedSignal

Resource Extensions

The second RFC pertains to resources, proposing a mechanism to extend them beyond the current capabilities of the snapshot function. For instance, an extension could modify a resource's behavior in an error state, allowing access to its value without throwing an error. The design also permits custom extensions, and there's an option to define default ones.

Both issues were filed by @markostanimirovic, who also appeared as a guest on a previous episode of the Angular Plus show. For a deeper dive into state management, especially regarding SignalStore, that episode is a recommended listen.

ngrx/platform#5126 — RFC resource extensions

Martina Kraus on security (Angular Plus Show)

In other news, the Angular Plus Show had Martina Kraus as a guest. Her presence typically signals a discussion on security, which was indeed the theme of the episode.

Alongside hosts Lara Newsom, Brooke Avery, and Jan-Niklas Wortmann, the conversation spanned a wide spectrum of security topics, including trusted types, sanitization, attacks such as XSS and CSRF, content policies, and the heightened risks introduced by AI.

Towards the end, Martina shared some initial steps for getting started with security, and highlighted the OWASP Juice Shop—an application built with Angular that serves as a sandbox for experimenting with various security vulnerabilities.

As a side note, storing your access token in local storage is not recommended.

OWASP Juice Shop | OWASP Foundation

Probably the most modern and sophisticated insecure web application for security trainings, awareness demos and CTFs. Also great voluntary guinea pig for your security tools and DevSecOps pipelines!

favicon owasp.org

Form validation: debouncing async validators

A third debounce mechanism has landed in Angular. Signal Forms already offer a debounce function that delays syncing a form control with its model. A debounced utility, aimed at any Signal, is slated for Angular 22. The newest addition specifically targets async validators in Signal Forms — so you can keep sync validators immediate while throttling async ones independently.

This feature is merged into the v22 branch but did not ship with the latest 21.2.7 release. It looks like Angular 22 is the target.

angular/angular@24e52d4 — debounce on validateAsync / validateHttp

Alfredo Perez: SpecKit and SpecKit Companion

@alfredoperez has written a three-part series on spec-driven development with AI. The central tool is GitHub's SpecKit, which Alfredo covers in depth. Alongside that, he built a VSCode extension called SpecKit Companion — designed not only for viewing specs but also for editing and executing them.

SpecKit isn't the only option in this space, so Alfredo walks through alternatives and explains how SpecKit Companion can be configured to work with those as well.

https://medium.com/ngconf/speckit-companion-e4fc99d1e061

https://medium.com/ngconf/custom-workflows-in-speckit-companion-266fda3b5eec

https://medium.com/ngconf/build-your-own-sdd-workflow-daa3fc1ae673

https://marketplace.visualstudio.com/items?itemName=alfredoperez.speckit-companion

Angular Graz Meetup videos

Recordings from the Angular Graz Meetup are now being uploaded to YouTube. They arrive on a steady schedule rather than all at once.