The inject() function retrieves a dependency from the active injection context without using a constructor, enabling cleaner code and use in functional guards, interceptors, and factory providers that are not classes. Outside an injection context, inject() throws unless given an explicit Injector, and the { optional: true } option prevents the error when the dependency may be missing. The classic modifier decorators still apply: @Self() limits the search to the current injector, @SkipSelf() starts from the parent injector, @Optional() injects null instead of throwing when not found, and @Host() stops the search at the host component. forwardRef(() => SomeClass) resolves a class reference later, useful when classes reference each other in the same file. Angular maintains a tree of injectors parallel to the component tree, so providers in providers: [] create a new injector for that component and its descendants, enabling scoped instances like one UserService per feature module. The viewProviders array is visible only to the component's own view and not to projected content, while providers is visible to both. InjectionToken creates a non-class DI token for injecting values, interfaces, or primitives, with provider configuration using useValue for a literal, useClass for a class instance, useFactory for a function-computed value, and useExisting to alias an existing token. The multi: true option creates a multi-provider, allowing multiple values to be associated with a single token, as used by HTTP_INTERCEPTORS and NG_VALIDATORS.
Change detection is Angular's mechanism for keeping the view in sync with component data. By default Angular uses a zone-based strategy that checks all components from root to leaves on every event, but ChangeDetectionStrategy.OnPush optimizes this by checking the component only when an @Input() reference changes, an event originates from the component, an Observable linked with AsyncPipe emits, or markForCheck() is called manually. ChangeDetectorRef.markForCheck() re-checks the component on the next cycle, while detach() and reattach() give full manual control. ApplicationRef.tick() triggers a full application-wide change detection cycle, generally avoided in production. NgZone is Angular's wrapper around Zone.js that tracks async operations to trigger change detection; NgZone.runOutsideAngular() runs code that should not trigger CD, and NgZone.run() re-enters the zone. In Angular 18, apps can run without Zone.js via provideExperimentalZonelessChangeDetection(), relying on signals and OnPush for change detection, which yields a smaller bundle and faster performance. For animation support, provideAnimations() enables the full engine, provideAnimationsAsync() lazy-loads it, and provideNoopAnimations() runs synchronously for tests. Common change-detection pitfalls include ExpressionChangedAfterItHasBeenCheckedError, which fires in dev mode when a binding's value changes after Angular read it, often caused by updating @Input-bound data in ngAfterViewInit and fixable with a deferred update.
The Angular CLI (ng) is the command-line tool for scaffolding and managing projects. ng new creates a new project, ng generate component, service, or module creates code via schematics, ng serve starts the dev server, ng build produces a production build, and ng test runs unit tests. ng add installs a package and runs its setup schematic, while ng update upgrades dependencies and runs migration schematics that automatically refactor code. Environment files like environment.ts and environment.prod.ts store configuration values that differ between environments, with Angular CLI automatically swapping the file during build. An Angular workspace in angular.json can contain multiple projects, including apps and libraries; ng generate library creates a publishable package built with ng-packagr. JIT compiles templates in the browser, slower with larger bundles, while AOT compiles at build time as the default for production, yielding smaller bundles and faster startup. Ivy is the current rendering engine, providing smaller bundles and better debugging. Angular Universal enables server-side rendering via provideClientHydration(), which reuses the server-rendered DOM on the client to preserve focus, scroll position, and event listeners; must-use withFetch() and avoid direct DOM access in lifecycle hooks. Angular 19 added incremental hydration, which defers server-side rendering of specific template blocks via @defer (hydrate on viewport) to reduce SSR cost. Testing relies on TestBed, which creates a testing module, and ComponentFixture returned by TestBed.createComponent() exposes componentInstance, debugElement, nativeElement, and detectChanges(). ComponentHarness from @angular/cdk/testing provides a stable, abstracted testing API that survives markup changes, while ng-mocks is a popular library for mocking modules and services. Global error handling implements the ErrorHandler interface to centralize logging, APP_INITIALIZER's modern replacement is provideAppInitializer(), and provideEnvironmentInitializer() runs after providers are configured but before bootstrap for side effects like telemetry registration.