TypeScript `StrictPropertyInitialization` in Real Codebases: Patterns That Pass the Compiler Without Lying An engineer documented five patterns for satisfying TypeScript's strictPropertyInitialization flag without resorting to definite assignment assertions, which silence the compiler while reintroducing the runtime undefined risk the flag exists to prevent. The writeup explains that the flag performs reachability analysis on class constructors, catching conditional initialization, initialization in post-construction methods, and properties dependent on external state. The recommended alternatives include definite assignment only when initialization is guaranteed, private initialization methods, optional properties matching runtime behavior, dependency injection with nullable types, and abstract class contracts deferring initialization to subclasses. This article was written with the assistance of AI, under human supervision and review. TypeScript's strictPropertyInitialization flag catches a specific class of bug: class properties that the compiler believes are defined but remain undefined at runtime. The flag forces developers to prove that every property without an explicit undefined type gets a value during construction. Most codebases respond by sprinkling definite assignment assertions across property declarations, which satisfies the compiler but reintroduces the exact risk the flag exists to prevent. The gap appears because developers treat strictPropertyInitialization as a compiler nuisance rather than a design constraint. When a property cannot be initialized in the constructor, the correct response is rarely "tell the compiler to trust you". Five patterns exist that satisfy the flag honestly: definite assignment only when initialization is guaranteed, private initialization methods, optional properties that match runtime behavior, dependency injection with nullable types, and abstract class contracts that defer initialization to derived classes. Each pattern preserves the type safety the flag provides while accommodating real initialization requirements. strictPropertyInitialization prevents runtime undefined access by forcing explicit initialization contracts in class constructors. are safe only when third-party decorators or framework lifecycle hooks guarantee initialization before property access. The flag performs a reachability analysis on class constructors. For every property declared without ? or | undefined in its type, TypeScript traces all constructor code paths to verify that the property receives a value before the constructor completes. If any path reaches the end without an assignment, the compiler reports an error. The analysis catches three specific failures. First, conditional initialization where some branches skip assignment. Second, initialization in methods called after construction. Third, properties that depend on external state not available during construction. All three scenarios produce runtime undefined where the type system claims a value exists. class DataLoader { // Error: Property 'data' has no initializer data: string ; constructor private shouldLoad: boolean { if shouldLoad { this.data = ; } // If shouldLoad is false, data stays undefined } } The compiler does not care about the logic that determines whether shouldLoad is true. It sees that a code path exists where data remains unassigned and reports the violation. This is correct behavior: the type string promises that data holds an array, but the constructor breaks that promise in the false branch. Developers encounter this most often in classes that perform asynchronous initialization. A common pattern loads configuration or fetches remote data in a method called after construction. The constructor cannot await these operations without blocking, so properties stay undefined until the async method completes. class APIClient { // Error: Property 'token' has no initializer token: string; constructor private endpoint: string {} async initialize { const response = await fetch ${this.endpoint}/auth ; this.token = await response.text ; } } The constructor completes before initialize runs, leaving token undefined. Any code that accesses this.token between construction and initialization sees undefined, contradicting the type. The flag surfaces this mismatch before production. TypeScript compiler analyzing class property initialization paths The definite assignment assertion tells the compiler "this property will have a value before any code accesses it, guaranteed by external mechanisms you cannot see". The assertion is honest in exactly one scenario: when a third-party system decorators, framework lifecycle hooks, dependency injection containers initializes the property before user code runs. Frontend frameworks demonstrate the legitimate use case. Angular's @Input decorator guarantees that the framework sets the property during component initialization, before lifecycle hooks or templates run. The developer never writes code that assigns the property, but the framework contract ensures initialization occurs. js import { Component, Input } from '@angular/core'; @Component { selector: 'user-card', template: '