Angular’s signals provide a reactive way to manage state. Signals can store and reactively update values of different data types including primitives, objects, and arrays. This makes them highly flexible for managing application state in a predictable way.
number and string.count()..set() or .update() to trigger reactivity.A signal is created using the signal<T>() function, where T is the data type it will hold.
signal<number>(0) → a numeric signal starting at 0.signal<string>('John Doe') → a string signal for a username.signal<{ name: string; age: number }>({...}) → an object signal.signal<string[]>([...]) → an array signal.When you change the signal’s value with .set() or .update(), Angular automatically re-renders any template bindings that depend on that signal.
// Primitive signals for count and username
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent {
count = signal<number>(0);
username = signal<string>('John Doe');
}
<!-- Bind to primitive signals in the template -->
<p>Count: {{ count() }}</p>
<button (click)="count.set(count() + 1)">Increment</button>
<p>Hello, {{ username() }}!</p>
// Store a user object inside a signal
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent {
user = signal<{ name: string; age: number }>({
name: 'Alice',
age: 25
});
}
<!-- Read and update properties from the user signal -->
<p>Name: {{ user().name }}</p>
<p>Age: {{ user().age }}</p>
<button (click)="user.set({ ...user(), age: user().age + 1 })">Increase Age</button>
// Manage a list of tasks using an array signal
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent {
tasks = signal<string[]>(['Learn Angular', 'Build Project']);
}
<!-- Loop over the tasks signal and render each item -->
<ul>
@for (task of tasks(); let i = $index) {
<li>{{ i + 1 }}. {{ task }}</li>
}
</ul>
<button (click)="tasks.set([...tasks(), 'New Task'])">Add Task</button>
count signal’s value increases and the template automatically shows the new number.user signal with a new object (using the spread operator), the displayed name and age refresh instantly.No manual change detection calls are needed: the signal system re-runs any computations or template bindings that depend on the changed signals.
.set() or .update() methods to modify signals instead of mutating the value directly.readonly signals for values that should not change, to keep your state predictable and safe.signal for a counter and build increment/decrement buttons.tasks.set([]) and observe how the UI updates.