TypeScript diagnostic and refresher¶
Use this reference only for a demonstrated prerequisite gap. First explain or implement the relevant item without notes; after review, prove the repaired model in an Angular lesson.
Model finite states¶
Prefer unions over strings and boolean combinations:
type TopicStatus = 'not-started' | 'learning' | 'confident';
type LoadState<T> =
| { status: 'loading' }
| { status: 'success'; data: T }
| { status: 'error'; message: string };
A switch on status narrows the available fields and can be checked exhaustively.
unknown before trust¶
External JSON, caught errors, and message events are not automatically domain objects. Use unknown, validate/narrow, then map. any disables the question.
Interfaces and readonly¶
Interfaces describe structural contracts. readonly prevents assignment through that reference but does not deep-freeze runtime objects. Immutable updates make signal notification and reasoning predictable.
Generics¶
LoadState<T> preserves the loaded data type. A generic should represent a relationship between types; do not add <T> merely to appear reusable.
Null safety¶
Handle missing route entities explicitly. Avoid ! unless an invariant truly exists outside TypeScript's knowledge and is enforced. Optional chaining is not a replacement for an intentional missing-data UI.
DOM event narrowing¶
An event handler receives Event; narrow at the boundary:
Better yet, reusable components can emit domain values so parents never see DOM event types.
Typed forms¶
Non-nullable controls prevent reset from introducing null. getRawValue() includes disabled controls; value may not. Form types protect client code, while runtime/server validation still protects system boundaries.
Verification challenge¶
Explain structural typing, covariance risks in mutable collections, never for exhaustiveness, type guard versus assertion, and compile-time type erasure at runtime using tracker examples. Then apply the weak item in typed forms or the HTTP trust boundary without a cast.