AI News Hub Logo

AI News Hub

Angular injection context lint rules: say goodbye to NG0203 error

DEV Community
Cyrille Tuzi

Angular is changing a lot these days. One of the major changes that most developers are already aware of is how to inject dependencies. // Before @Component() export class ProductPage { constructor(private readonly productsApi: ProductsApi) {} } // Now @Component() export class ProductPage { private readonly productsApi = inject(ProductsApi); } The constructor-based injection was more limited, but it was safe on the compilation level. On the other hand, inject() and similar functions must be called from an injection context. Using them outside an injection context will compile just fine, but it will throw a runtime error that most developers have already encountered: the NG0203 error. This is a setback, as it is more difficult to debug, and as errors can be deployed and can happen in production. The injection context is available in: Angular classes properties initializers and constructors guards, resolvers, interceptors and routing options factories some application providers explicit injection context via runInInjectionContext() @Component() export class ProductPage { private readonly productsApi = inject(ProductsApi); // OK constructor(): void { inject(ProductsApi); // OK } } The injection context is not available in: any other methods than constructor (including component lifecycle methods and events methods) asynchronous callbacks or after an await non-Angular classes or functions @Component() class ProductPage { constructor() { somePromise.then(() => { inject(ProductsApi); // Runtime error }); } ngOnInit(): void { inject(ProductsApi); // Runtime error } onSubmit(): void { inject(ProductsApi); // Runtime error } async saveProduct(): Promise { await postToApi(); inject(Router); // Runtime error } } function save(): void { inject(ProductApi); // Runtime error } inject() is not the only function affected. Most of the new Angular functions require an injection context, notably: effect() signal form() resource() and rxResource() takeUntilDestroyed() toSignal() and toObservable() Third-party libraries based on signals or observables are often affected too. So the injection context is becoming a central concept of Angular. For these reasons, I created and published new lint rules: angular-eslint-injection-context. Following the 2 steps README on GitHub, it just takes a minute to install and configure, and then: the editor now shows when inject() and similar functions are used in the wrong places if the lint is included in the CI, the project is protected from deploying injection errors in production It reconciles the flexibility of the new dependency injection system with the safety and reliability of a compilation-oriented approach. Find this post and tool useful? I’m open to freelance & full-time opportunities. Feel free to reach out on LinkedIn or Bluesky.