inject() and the Injection Context In short: looks like a nicer way to write constructor parameters. It is much more than that — it is the reason the whole modern Angular API can exist. What changed on the surface Shorter. It also works much better with class inheritance — a base class that needs three services no longer forces every child class to repeat all three and call correctly. That alone was worth it. But the real change is what it made possible. The change that actually mattered Because works in field declarations , a function assigned to a field can reach Angular's service list. That is the mechanism behind everything in Chapter 4: None of these could be a constructor parameter. has to register information with the component itself. has to hook into the rendered view. needs and a cleanup hook. All three call behind the scenes, and all three only work because a field declaration is a legal place to do that. This is why "use or the constructor, it is just taste" is only true for simple cases. Once you write modern Angular, most of what you declare has to be a field. What an "injection context" is An injection context is a window of time when Angular has an active service list ready. reads from it. Outside that window there is nothing to read, and you get: The windows are: A class field declaration, for a class Angular creates (component, directive, pipe, service) A constructor body, for the same A factory function Inside Not a window: any method called later. , a click handler, a callback, a , the inside of a . Fixing NG0203 The fix is nearly always "ask for it at the field, use it later" — not : is for the genuinely changing case — code that decides at run time which service list to use. That is usually library or plugin code: If you find yourself wrapping normal app code in to silence NG0203, that is a sign the service should have been asked for at the field. The wrapper works, but it hides a design mistake. One thing to watch: field order There is a case where in a field really does differ from the constructor: fields are created top to bottom , before the constructor body runs. So a field that needs another field's value must come after it: In practice this rarely bites, because the reactive functions take small functions that run later, not values read straight away. But when it does bite, the error is confusing, and swapping the two lines is the fix. The old parameter decorators They all have function versions now, passed as options: is the one that really earns its place, because the type becomes on its own. With , TypeScript had no idea the value could be missing unless you wrote that yourself — and most people did not. What did not change Everything underneath. Angular still looks for services the same way: from the component outward, then up to the app level, then the platform. on a component still creates a new local list. still makes one shared instance. Injection tokens and / / all behave exactly as before. is a different way to ask . It is not a different way to find . "But isn't inject() vs constructor just taste?" For a plain service, yes — pick one and stay consistent. That view breaks down in three places. 1. Half the modern API cannot be a constructor parameter. , , , , — every one is a field that calls inside. There is no constructor version. So "I prefer constructors" stops being an option the moment you write a modern component, and you end up with both styles in one class for no reason. 2. Inheritance. With constructors, a base class that needs three services forces every child class to repeat all three: Add one service to the base class and every child class breaks. 3. gives you a truthful type. did not: The other myth: " is how you fix NG0203." It fixes one case — code that picks a service at run time, which is mostly library code. In app code, NG0203 almost always means you asked in the wrong place. The rule people learn the hard way Here is a case that looks correct and is not — a route resolver that picks a different strategy per customer: A resolver is an injection context — that is why works at the top of one. But the ends it. After the promise finishes, the code continues on a later turn of the browser's job queue, and the service list is no longer available. The rule: an injection context lasts only as long as your code runs without pausing. Anything after an , inside a , in a , or in a is outside it — even if the function it sits in started inside one. This is worth knowing because the error points at the call, not at the that invalidated it. The fix grabs the injector while still inside the window: This is the fair use of — the service genuinely is not known until run time. (In v22, fits this shape better.) The architect's view The decision this settles is where a class states its dependencies. Both styles work; they are not equally capable. Why standardise on : It is the only option for most modern APIs. , , , , and are field declarations that call internally. Ther…