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
TypeScript 6.0 was released and it is going to be the last TypeScript version, written in TypeScript. Officially, TypeScript 6 is seen as the bridge between TypeScript 5 and TypeScript 7 (which will be written in Go). First of all, TypeScript 6 is not yet part of Angular. So you can't make use of those changes yet. Angular 21 supports TypeScript 5.9, but 22 will support TypeScript 6.
In order to prepare for version 7, TypeScript 6 comes primarily with a lot of deprecations and new default settings, which pay tribute to the modern TypeScript ecosystem.
For example, ESM is now default module system, the strict mode is enabled and the target is the ECMAScript version with the number of the current last year. By now, that would be ECMAScript 2025.
When it comes to the deprecation. Target ES5, which was the last version of JavaScript without the class syntax, lambda expressions, Promises, let or const, string interpolation, and much more got deprecated.
What also went away is the baseUrl property in the tsconfig.json file, support for the module systems amd, umd, and systemjs (not sure if our younger colleagues still know what that is) has also gone. You can of course also revert those deprecations, but be aware that in TypeScript 7, that means game over.
There is an automatic migration tool available, which is marked as experimental.
There are also new features, and the most prominent one is the introduction of the Temporal API.
This is a new, built-in date and time API in JavaScript, which can be seen as a full replacement for the old Date object. As that, it provides way more functionality for example handling timezones, a calendar which can be used to reflect Chinese or other calendar systems, immutability and a range of utility functions.
Some veterans of us might remember the switch to the Date-time API in Java more than 10 years ago. It kind of did the same thing.
Temporal API has reached stage 4 of the TC39 process, which means it is standardized, finished. That doesn't mean that each platform supports it. The latest version of Chrome, Firefox supports it, but not Safari and also Node.js which means if you use it, you should secure your code 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`);
NgRx RFCs
NgRx is the most used library for state management in Angular and official work has begun on supporting resources but also forms. Two RFCs for that have landed.
delegatedSignal()
The first RFC is related to supporting Signal Forms and it introduces a new Signal type called delegatedSignal. To the outside it is a writable Signal, but it doesn't store a value. Instead it writes and reads to another Signal. What's the use of it?
Let's say we have a user object in a Signal, that has two nested properties: name and address. name has firstName and lastName, and address has street and city, like this:
const user = signal({
name: { firstName: 'John', lastName: 'Doe' },
address: { street: '123 Main St', city: 'Anytown' }
});
If we have a form, which requires a flattened version of the user object, we would usually create a linkedSignal. The problem is that changes in the form might be synchronized back to the original Signal. At the moment, the only way would be 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 }
})
})
}
delegatedSignal solves this problem by writing synchronously back to the original 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);
}
The delegatedSignal can be used for different use cases. Not just forms. Regarding the SignalStore, you could connect a Signal Form and a SignalStore together, where each change in the form is directly written to the SignalStore.
You can see the delegatedSignal as a linkedSignal which doesn't create a clone, but just writes directly back to the original Signal. delegatedSignal exists already in the Angular framework (slightly differently as deepSignal), but is not exposed publicly. Angular uses it for the Signal Forms:
https://github.com/angular/angular/blob/394ad0c2a26eec8a8f7136b1b7971420b30a117e/packages/forms/signals/src/util/deep_signal.ts#L21
ngrx/platform#5121 — RFC delegatedSignal
Resource Extensions
And the second RFC is related to resources. It allows to extend the resources which goes beyond the possibilities of the current snapshot function. For example, an extension would change the behavior of a resource in an error state, where an access to the value does not throw. Custom extensions are possible as well and there is even the option to define default extensions.
All two issues were created by @markostanimirovic and if the same Marko was also guest at a previous episode of the Angular Plus show. So if you are interested to hear more about state management and SignalStore specifically, you should check out the episode.
ngrx/platform#5126 — RFC resource extensions
Martina Kraus on security (Angular Plus Show)
In other news, the Angular Plus Show also had Martina Kraus as guest, which usually means the topic is about security.
Together with the three hosts, Lara Newsom, Brooke Avery, and Jan-Niklas Wortmann, they discussed a whole portfolio of security. Be it trusted types, Sanitization, attacks like XSS and CSRF, but also content policies and the increased risk that comes with AI.
At the end, Martina gave some tips where to start with security and she also highlighted the OWASP juice shop, which is written in Angular and is a playground to try out different vulnerabilities.
And by the way, you should not store your access token in local storage.
Form validation: debouncing async validators
And we have a third debounce option in Angular. For Signal Forms, there is a debounce function, which debounces the synchronization of a form field with the underlying model. The second is a debounced function, scheduled for Angular 22 and is meant for any Signal type out there. The new one, is debouncing for asynchronous validators in Signal Forms. That allows you to have "undebounced" synchronous validators, but debouncing an asynchronous validator.
That feature has been merged into the 22 version branch, but didn't make it into the latest 21.2.7 version. So it seems, we have to wait for Angular 22.
angular/angular@24e52d4 — debounce on validateAsync / validateHttp
Alfredo Perez: SpecKit and SpecKit Companion
@alfredoperez published a three-article series about a Spec-driven development process with AI. The most prominent tool in that spectrum is GitHub's SpecKit, which Alfredo describes. Additionally, he has created a VSCode extension, called SpecKit Companion, not just to visualize but also to edit and execute that specification.
Since GitHub's SpecKit is not the only tool out there, Alfredo also shows alternatives and how SpecKit Companion can be configured to support those tools 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
Finally, the recordings of the Angular Graz Meetup are available on YouTube. They are published not at once but in a regular interval.
Top comments (0)