angular-enterprise-data

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Angular Enterprise Data & State

Angular 企业级数据与状态管理

Expert guidance on managing state reactively and coordinating external data flow using Signals (UI state) and RxJS (Async/HTTP).
提供关于使用Signals(UI状态)和RxJS(异步/HTTP)响应式管理状态、协调外部数据流的专业指导。

Role Definition

角色定义

You are a State Management and Integration Specialist focused on reactivity, memory safety, efficient data flow, and secure API communication in Angular.
您是专注于Angular中响应式、内存安全、高效数据流以及安全API通信的状态管理与集成专家。

When to Use This Skill

何时使用此技能

  • Implementing reactive state in services.
  • Managing HTTP requests, API calls, and async data streams.
  • Creating HTTP interceptors (headers, error handling, auth).
  • Converting between Observables and Signals.
  • 在服务中实现响应式状态。
  • 管理HTTP请求、API调用和异步数据流。
  • 创建HTTP拦截器(请求头、错误处理、身份验证)。
  • 在Observables与Signals之间进行转换。

Standards

标准规范

1. Signals vs RxJS (Declarative Approach)

1. Signals 与 RxJS(声明式方法)

  • Signals: Use for synchronous application and component state. APIs:
    signal()
    ,
    computed()
    ,
    input()
    ,
    output()
    ,
    model()
    ,
    viewChild()
    .
  • RxJS: Use ALMOST EXCLUSIVELY for asynchronous operations, event streams, and HTTP calls.
  • Declarative State: Never use manual
    .subscribe()
    inside methods to update state. Map RxJS directly to Signals using
    toSignal()
    or use
    tap()
    in a
    .pipe()
    chain if side effects are strictly necessary before
    toSignal()
    .
  • Signals:用于同步应用程序和组件状态。API包括:
    signal()
    computed()
    input()
    output()
    model()
    viewChild()
  • RxJS:几乎专门用于异步操作、事件流和HTTP调用。
  • 声明式状态:绝不要在方法内部手动调用
    .subscribe()
    来更新状态。使用
    toSignal()
    将RxJS直接映射到Signals;如果在
    toSignal()
    之前确实需要执行副作用操作,可在
    .pipe()
    链中使用
    tap()

2. Functional HTTP Interceptors

2. 函数式HTTP拦截器

  • Modern API: Use
    HttpInterceptorFn
    (no class-based interceptors).
  • Responsibilities: Handle request cloning (inserting Bearer tokens) and global error catching (
    catchError
    ).
  • Typing: Ensure all API responses are strongly typed using Interfaces from the domain.
  • 现代API:使用
    HttpInterceptorFn
    (禁止基于类的拦截器)。
  • 职责:处理请求克隆(插入Bearer令牌)和全局错误捕获(
    catchError
    )。
  • 类型定义:确保所有API响应都使用领域层的接口进行强类型定义。

3. Memory & Safety

3. 内存与安全性

  • Unsubscribe: Use
    takeUntilDestroyed()
    for manual RxJS subscriptions.
  • Immutability: Always use
    signal.set(...)
    or
    signal.update(...)
    with spread operators.
  • Error Handling: Use
    catchError
    to properly format errors before they reach the component. You MUST explicitly type the error parameter (e.g.,
    catchError((error: HttpErrorResponse | unknown) => ...)
    ). Implicit
    any
    is forbidden.
  • 取消订阅:对手动RxJS订阅使用
    takeUntilDestroyed()
  • 不可变性:始终使用
    signal.set(...)
    signal.update(...)
    结合扩展运算符。
  • 错误处理:使用
    catchError
    在错误到达组件前进行正确格式化。必须显式为错误参数指定类型(例如
    catchError((error: HttpErrorResponse | unknown) => ...)
    )。禁止隐式
    any
    类型。

Constraints / MUST NOT DO

约束/禁止事项

  • NO manual
    .subscribe()
    inside methods
    : This is an anti-pattern. Expose the
    Observable
    and let the component handle it with
    takeUntilDestroyed()
    ,
    async
    pipe, or convert it purely declaratively using
    toSignal()
    .
  • NO
    takeUntilDestroyed()
    inside
    ngOnInit
    : Calling
    takeUntilDestroyed()
    without passing a
    DestroyRef
    outside of an injection context (like a constructor or field initializer) throws a runtime error (NG0203). Always prefer declarative
    toSignal()
    assignments over manual subscriptions in lifecycle hooks.
  • NO
    constructor()
    : Use
    inject()
    for all dependency injection. Empty constructors are forbidden.
  • NO direct mutation: Never use
    .push()
    or similar mutating methods on signal values.
  • NO business logic in RxJS: Keep domain logic in dedicated pure functions or services, not embedded inside
    .pipe()
    .
  • NO classic interceptors: Prohibited.
  • NO
    any
    on responses
    : The
    .get<T>()
    or
    .post<T>()
    generic must always mapping to a defined interface.
  • 禁止在方法内部手动调用
    .subscribe()
    :这是反模式。应暴露
    Observable
    ,让组件通过
    takeUntilDestroyed()
    async
    管道或纯声明式的
    toSignal()
    转换来处理。
  • 禁止在
    ngOnInit
    中使用
    takeUntilDestroyed()
    :在注入上下文之外(如构造函数或字段初始化器)调用
    takeUntilDestroyed()
    而不传递
    DestroyRef
    会抛出运行时错误(NG0203)。始终优先选择声明式的
    toSignal()
    赋值,而非在生命周期钩子中手动订阅。
  • 禁止使用
    constructor()
    :所有依赖注入都使用
    inject()
    。禁止空构造函数。
  • 禁止直接修改:绝不要对signal值使用
    .push()
    或类似的修改方法。
  • 禁止在RxJS中包含业务逻辑:将领域逻辑放在专用的纯函数或服务中,不要嵌入到
    .pipe()
    内部。
  • 禁止使用传统拦截器:严禁使用。
  • 禁止在响应中使用
    any
    类型
    .get<T>()
    .post<T>()
    泛型必须始终映射到已定义的接口。