
Angular 19 引入了 linkedSignal 原语,可直接获取上一次计算结果;旧版本则可通过 ngxtension 的 extendedComputed 实现类似 RxJS scan 的累积逻辑。
angular 19 引入了 `linkedsignal` 原语,可直接获取上一次计算结果;旧版本则可通过 `ngxtension` 的 `extendedcomputed` 实现类似 rxjs `scan` 的累积逻辑。
在响应式状态管理中,有时我们需要基于“当前输入 + 上一次输出”进行计算——例如将新值追加到数组、实现带记忆的累加器,或仅在条件满足时更新结果。这正是 RxJS 中 scan 操作符的经典场景。Angular 信号(Signal)原生不支持直接访问历史值,但不同版本提供了成熟解法。
✅ Angular 19+:使用 linkedSignal(官方推荐)
Angular 19 新增的 linkedSignal 是专为此类需求设计的底层原语。它接收一个 source 信号和一个 computation 函数,该函数签名明确提供 (currentSourceValue, previousComputedValue) => newValue,天然支持状态延续:
import { signal, computed, linkedSignal } from '@angular/core';
const signalA = signal('item-1');
const signalB = signal<string>([]);
// 将 signalA 的每次新值追加到 signalB 的数组中
const accumulatedList = linkedSignal({
source: signalA,
computation: (newItem, previousList = []) => [...previousList, newItem]
});
// 使用示例
console.log(accumulatedList()); // ['item-1']
signalA.set('item-2');
console.log(accumulatedList()); // ['item-1', 'item-2']
signalA.set('item-3');
console.log(accumulatedList()); // ['item-1', 'item-2', 'item-3']</string>
⚠️ 注意:linkedSignal 的 computation 仅在 source 变更时触发,且 previousValue 是上一次该 linkedSignal 的返回值(非 source 的历史值),因此它严格对应“上一次计算结果”,语义清晰、无歧义。
⚙️ Angular ngxtension/computed
若仍在使用 Angular 18 或更早版本,可引入社区维护的高质量工具库 ngxtension,其 extendedComputed 提供了与 linkedSignal 高度一致的 API:
npm install ngxtension
import { signal } from '@angular/core';
import { extendedComputed } from 'ngxtension/computed';
const signalA = signal('alpha');
const signalB = signal<string>(['init']);
// 累积式更新:每次取 signalA 当前值,拼接到 signalB 的上一次结果中
const result = extendedComputed<string>((prev) => [...prev, signalA()]);
// 初始值需显式设置(因无 source 依赖,首次调用 prev 为 undefined)
// 推荐初始化方式:
const initializedResult = extendedComputed<string>((prev = ['init']) => [...prev, signalA()]);</string></string></string>
? 提示:extendedComputed 的回调函数不接收参数信号引用,而是通过闭包捕获外部信号(如 signalA()),因此务必确保信号读取发生在函数体内,以建立正确的依赖追踪。
? 关键总结
-
linkedSignal(v19+)是官方方案,语义明确、类型安全、零依赖,应作为首选; -
extendedComputed(- 二者均避免了手动维护中间状态信号(如
lastValue = signal())的繁琐与潜在竞态风险;- ❌ 不要尝试用
computed(() => [...signalB(), signalA()])—— 这会创建无限递归依赖(signalB依赖自身),导致运行时错误。 - 二者均避免了手动维护中间状态信号(如
无论版本如何,现在你都可以优雅地实现信号间的“有状态计算”,让 Angular 信号真正胜任复杂的状态流建模任务。










