An Angular-specific linter enforcing optimal reactivity patterns with Signals and RxJS
- 🛠 Architecture Guards
- Enforce
takeUntilDestroyed()for subscription cleanup - Require
OnPushwithasyncpipes
- Enforce
- ⚡ Performance Optimizations
- Detect unnecessary change detection triggers
- Identify overused RxJS operators
- 🚦 Migration Ready
- Suggest Signal conversions for RxJS chains
- Highlight deprecated reactivity patterns
ng add ng-reactive-lintnpm install -g ng-reactive-lint
Use npx to run reactive-lint directly after installing it:
# Lint a specific file
npx reactive-lint src/app/my-component.tsnpx reactive-lint "src/app/**/*.ts"
npx reactive-lint "src/**/*.ts"
| Rule ID | Description | Fixable | Angular-Only |
|---|---|---|---|
| no-implicit-subscriptions | Requires takeUntilDestroyed() |
✅ | Yes |
| no-async-without-onpush | Flags missing OnPush |
❌ | Yes |
| prefer-signal | Suggests Signal conversions | ✅ | No |
| no-unused-observables | Detects unused RxJS streams | ❌ | No |
| Metric | Bad Code (Legacy RxJS) | Good Code (Modern Signals) |
|---|---|---|
| Linting Time (avg) | 1.21 s | 1.86 s |
| Memory Usage | 152 MB | 251 MB |
⚠️ Note: The "good" code uses modern Angular patterns (toSignal,effect) which involve deeper AST structures and more reactive expressions. This naturally increases parsing time but reflects real-world adoption of Signals. The linter scales robustly with complexity.
npm run buildnpm testnpm run lint-example
PRs welcome! See our Contribution Guide.