Un computed est une valeur dérivée, calculée automatiquement à partir d’un ou plusieurs signals.
✔ Ce n’est pas une fonction
✔ Ce n’est pas un effect
✔ Ce n’est pas un setter
👉 C’est une formule réactive.
Il s’exécute :
- immédiatement (1ère fois)
- à chaque fois qu’un signal utilisé à l’intérieur change
- si et seulement si le computed est lu dans le template ou dans un effect (lazy)
const price = signal(10);
const qty = signal(2);
const total = computed(() => price() * qty());Lecture :
total(); // 20Si qty.set(3) → total() devient automatiquement 30.
Avec les computed, tu crées une architecture :
input()= données venant du parentsignal()= état interne modifiablecomputed()= logique dérivée, jamais mutéeeffect()= effets de bord
Un computed est la seule manière correcte de calculer une valeur réactive.
Uniquement une expression pure et déterministe :
- accès à des signals (
a(),b(), …) - transformations
- mapping
- concaténation
- logique métier "stateless"
✔ Pas d’API call
✔ Pas de mutation
✔ Pas d’output.emit
✔ Pas d’effet de bord
Avant :
ngOnChanges() {
this.total = this.price * this.qty;
}Après :
readonly total = computed(() => this.price() * this.qty());Avantages :
- zéro hook
- zéro maintenance
- zéro risque d’oubli
- toujours juste
- réactif finement
- beaucoup plus clair
@Input() customer!: Customer;
@Input() legalUnitAddress!: Address;
shippingAddress!: Address | null;
ngOnChanges() {
this.shippingAddress = this.customer?.shippingAddress
?? this.legalUnitAddress
?? null;
}readonly customer = input<Customer>();
readonly legalUnitAddress = input<Address>();
readonly shippingAddress = computed(() =>
this.customer()?.shippingAddress
?? this.legalUnitAddress()
?? null
);Template :
Un computed :
- ne calcule pas automatiquement tant qu’il n’est pas utilisé
- se désactive automatiquement si aucun observer ne l’utilise
Exemple :
const expensive = computed(() => veryHeavyOperation());→ Ne fait rien tant que tu ne fais pas expensive().
computed(() => {
console.log("Hello"); // ❌ NE JAMAIS FAIRE
});✔ Les logs doivent aller dans un effect().
computed(() => this.count.set(5)); // ❌ boucle infinie / architecture pourrieUn output n’est pas un signal lisible → interdit.
computed(async () => { ... }); // ❌Un computed doit être 100 % synchrone.
readonly fullName = computed(() => {
const u = this.user();
return u ? `${u.firstName} ${u.lastName}` : '';
});readonly filtered = computed(() =>
this.items().filter(i => i.selected)
);readonly statusLabel = computed(() => {
if (this.loading()) return 'Chargement...';
if (this.error()) return 'Erreur';
return 'OK';
});readonly formatted = computed(() =>
formatAddress(this.address())
);Tu ne te poses plus la question du "quand recalculer ?" → Angular le fait.
✔ signal() → une valeur que tu modifies
✔ input() → une valeur que tu reçois
✔ computed() → une valeur que tu calculs
✔ effect() → une action que tu déclenches
Un computed = une formule.
Un signal = une variable.
Un effect = un effet de bord.
Un input = une source externe.